{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://observerprotocol.org/schemas/delegation/v2.4.json",
  "title": "Observer Protocol Delegation Credential v2.4",
  "description": "v2.4 extends v2.1/v2.3: ADDS the spending-delegation container (credentialSubject.delegation.scope.spending_limits.per_rail, closed shape) so one credential carries both the structural envelope the verifier requires AND the per-rail/per-asset limits the hosted engine reads. authorizationLevel/authorizationConfig no longer forced on shapes that omit them (the allOf if-branches now require authorizationLevel to be PRESENT before firing). CORRECTS the proof block to describe the issued suite (DataIntegrityProof / eddsa-jcs-2022, base58btc multibase proofValue); the legacy Ed25519Signature2020/2026 proof shape was inherited from v2.1/v2.3 unexamined and is fixed here. New URL; v2.3 frozen. Does NOT relax the envelope.",
  "type": "object",
  "required": [
    "@context",
    "id",
    "type",
    "issuer",
    "validFrom",
    "validUntil",
    "credentialSubject",
    "credentialSchema",
    "proof"
  ],
  "properties": {
    "@context": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string"
      },
      "contains": {
        "enum": [
          "https://www.w3.org/ns/credentials/v2"
        ]
      }
    },
    "id": {
      "type": "string",
      "format": "uri",
      "pattern": "^https://|^urn:uuid:"
    },
    "type": {
      "type": "array",
      "minItems": 2,
      "contains": {
        "const": "VerifiableCredential"
      }
    },
    "issuer": {
      "type": "string",
      "pattern": "^did:[a-z]+:.+"
    },
    "validFrom": {
      "type": "string",
      "format": "date-time"
    },
    "validUntil": {
      "type": "string",
      "format": "date-time"
    },
    "credentialSubject": {
      "type": "object",
      "required": [
        "id",
        "actionScope",
        "delegationScope",
        "enforcementMode"
      ],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^did:[a-z]+:.+"
        },
        "authorizationLevel": {
          "type": "string",
          "enum": [
            "one-time",
            "recurring",
            "policy"
          ],
          "description": "Authorization scope granted by the principal. Level 1 (one-time) authorizes a single transaction. Level 2 (recurring) authorizes repeat transactions with one counterparty up to a ceiling. Level 3 (policy) references a broader standing policy."
        },
        "authorizationConfig": {
          "type": "object",
          "description": "Level-specific configuration. Exactly one of oneTime, recurring, or policy must be present, matching authorizationLevel. Enforced via if/then at the credentialSubject level.",
          "properties": {
            "oneTime": {
              "type": "object",
              "description": "Level 1: single-transaction authorization. The credential is consumed after one successful settlement.",
              "properties": {
                "counterparty_did": {
                  "type": "string",
                  "pattern": "^did:",
                  "description": "DID of the specific counterparty for this transaction"
                },
                "amount": {
                  "type": "string",
                  "description": "Exact transaction amount (e.g. '50.00')"
                },
                "currency": {
                  "type": "string",
                  "description": "ISO-4217 currency or asset code (e.g. 'USD', 'USDT')"
                },
                "rail": {
                  "type": "string",
                  "description": "Settlement rail for this transaction (e.g. 'usdt-trc20', 'lightning')"
                },
                "execution_deadline": {
                  "type": "string",
                  "format": "date-time",
                  "description": "Credential expires if not used by this time. Short window (e.g. 15 minutes)."
                },
                "purchase_description": {
                  "type": "string",
                  "description": "Human-readable description of what is being purchased"
                }
              },
              "required": [
                "counterparty_did",
                "amount",
                "currency",
                "rail"
              ]
            },
            "recurring": {
              "type": "object",
              "description": "Level 2: counterparty-scoped recurring authorization. Authorizes future transactions with one specific counterparty up to a ceiling per period.",
              "properties": {
                "counterparty_did": {
                  "type": "string",
                  "pattern": "^did:",
                  "description": "DID of the specific counterparty"
                },
                "ceiling_amount": {
                  "type": "string",
                  "description": "Maximum aggregate spend per period (e.g. '500.00')"
                },
                "ceiling_currency": {
                  "type": "string",
                  "description": "ISO-4217 currency for ceiling"
                },
                "per_transaction_max": {
                  "type": "string",
                  "description": "Optional per-transaction cap within the ceiling"
                },
                "period": {
                  "type": "string",
                  "description": "ISO-8601 duration for ceiling reset (e.g. 'P30D' for monthly)"
                },
                "valid_until": {
                  "type": "string",
                  "format": "date-time",
                  "description": "When this recurring authorization expires entirely"
                },
                "allowed_rails": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Rails permitted for recurring transactions with this counterparty"
                }
              },
              "required": [
                "counterparty_did",
                "ceiling_amount",
                "ceiling_currency",
                "period"
              ]
            },
            "policy": {
              "type": "object",
              "description": "Level 3: broader standing policy. The policy_id references an internal policy document stored in Sovereign. Counterparties see only the policy_id and the external credential fields \u2014 never the full policy logic.",
              "properties": {
                "policy_id": {
                  "type": "string",
                  "description": "Reference to the internal policy document in Sovereign"
                },
                "rail_preference": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Priority-ordered rail preference list. First match against counterparty's accepted rails wins. E.g. ['usdt-trc20', 'lightning'] means prefer USDT, fall back to Lightning."
                },
                "per_rail_caps": {
                  "type": "object",
                  "description": "Per-rail spending caps. Keys are rail identifiers.",
                  "additionalProperties": {
                    "type": "object",
                    "properties": {
                      "per_transaction": {
                        "type": "string",
                        "description": "Max per single transaction on this rail"
                      },
                      "aggregate": {
                        "type": "string",
                        "description": "Max aggregate spend on this rail per period"
                      },
                      "period": {
                        "type": "string",
                        "description": "ISO-8601 duration for aggregate reset"
                      },
                      "currency": {
                        "type": "string"
                      }
                    }
                  }
                },
                "escalation_threshold": {
                  "type": "object",
                  "description": "Transactions above this amount trigger human notification before execution",
                  "properties": {
                    "amount": {
                      "type": "string"
                    },
                    "currency": {
                      "type": "string"
                    }
                  }
                },
                "fallback_rules": {
                  "type": "array",
                  "description": "Conditional rail selection rules evaluated in order",
                  "items": {
                    "type": "object",
                    "properties": {
                      "condition": {
                        "type": "string",
                        "description": "Condition expression (e.g. 'usdt_balance < amount')"
                      },
                      "then_rail": {
                        "type": "string",
                        "description": "Rail to use if condition is true"
                      }
                    },
                    "required": [
                      "condition",
                      "then_rail"
                    ]
                  }
                },
                "time_windows": {
                  "type": "object",
                  "description": "Aggregate caps per time window across all counterparties",
                  "properties": {
                    "daily": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "string"
                        },
                        "currency": {
                          "type": "string"
                        }
                      }
                    },
                    "weekly": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "string"
                        },
                        "currency": {
                          "type": "string"
                        }
                      }
                    },
                    "monthly": {
                      "type": "object",
                      "properties": {
                        "amount": {
                          "type": "string"
                        },
                        "currency": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              },
              "required": [
                "policy_id",
                "rail_preference"
              ]
            }
          }
        },
        "actionScope": {
          "type": "object",
          "description": "Spending-mandate surface. See aip-v0.8-draft-1.md \u00a71.1\u2013\u00a71.3. Closed shape: additionalProperties is false; new fields require a numbered-draft schema update.",
          "properties": {
            "allowed_rails": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Binding. Proposed action's rail MUST be in this list."
            },
            "per_transaction_ceiling": {
              "type": "object",
              "description": "Binding. Per-action amount ceiling, same-currency comparison only \u2014 no FX. See \u00a71.2 and \u00a73.2.",
              "properties": {
                "amount": {
                  "type": "string",
                  "description": "Decimal amount as string."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code, token symbol, or rail-native unit."
                }
              },
              "required": [
                "amount",
                "currency"
              ],
              "additionalProperties": false
            },
            "allowed_transaction_categories": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Binding. Proposed transaction-category MUST be in this list."
            },
            "cumulative_budget": {
              "type": "object",
              "description": "Advisory. Declared total spend cap over the credential's validity window. v0.8 does NOT define binding enforcement (\u00a71.2). MUST NOT ground a deny verdict.",
              "properties": {
                "amount": {
                  "type": "string",
                  "description": "Decimal amount as string."
                },
                "currency": {
                  "type": "string",
                  "description": "Must match per_transaction_ceiling.currency for advisory accumulation; cross-currency prior spends reported as uncountable."
                },
                "window": {
                  "type": "string",
                  "enum": [
                    "credential_validity"
                  ],
                  "description": "v0.8 locks this to the credential's validFrom\u2192validUntil envelope. Rolling-/calendar-window semantics are reserved for a future draft."
                }
              },
              "required": [
                "amount",
                "currency",
                "window"
              ],
              "additionalProperties": false
            },
            "allowed_counterparty_types": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "verified_merchant",
                  "kyb_verified_org",
                  "peer_agent",
                  "sovereign_self_attested"
                ]
              },
              "description": "Reserved \u2014 ADVISORY in v0.8 (\u00a71.3). Declaration of intended counterparty classes; MUST NOT ground a deny verdict."
            },
            "geographic_restriction": {
              "type": "object",
              "description": "Reserved \u2014 ADVISORY in v0.8 (\u00a71.3). Spending-surface geographic intent; MUST NOT ground a deny verdict. Trading-surface geographic enforcement (\u00a72.3) is unaffected.",
              "properties": {
                "allowed": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "description": "ISO 3166-1 alpha-2 country codes."
                },
                "disallowed": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "description": "ISO 3166-1 alpha-2 country codes."
                }
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false
        },
        "delegationScope": {
          "type": "object",
          "required": [
            "may_delegate_further"
          ],
          "properties": {
            "may_delegate_further": {
              "type": "boolean"
            },
            "max_child_action_scope": {
              "type": "object"
            },
            "may_delegate_delegation_authority": {
              "type": "boolean"
            },
            "allowed_child_subject_types": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "acl": {
          "type": "object",
          "properties": {
            "revocation_authority": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^did:"
              }
            },
            "modification_authority": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^did:"
              }
            }
          }
        },
        "enforcementMode": {
          "type": "string",
          "enum": [
            "protocol_native",
            "pre_transaction_check"
          ]
        },
        "parentDelegationId": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "kybCredentialId": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri"
        },
        "tradingMandate": {
          "type": "object",
          "description": "AIP v0.7 \u2014 optional trading-domain mandate. Expresses the scope of a delegated agent's trading authority. Verification is unchanged; the field is signed under the existing credential proof. See aip-v0.7-draft-1.md.",
          "properties": {
            "allowedVenues": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Closed list of venue identifiers the agent MAY transact on. A venue not present is denied."
            },
            "allowedInstruments": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Closed list of permitted assets, pairs, or instrument classes."
            },
            "maxNotionalPerOrder": {
              "type": "integer",
              "minimum": 0,
              "description": "Maximum notional value of any single order, denominated by `unit`."
            },
            "maxPosition": {
              "type": "integer",
              "minimum": 0,
              "description": "Maximum aggregate open exposure under this mandate, denominated by `unit`."
            },
            "unit": {
              "type": "string",
              "description": "Denomination currency or asset code for maxNotionalPerOrder and maxPosition. REQUIRED whenever either is present; verifiers MUST NOT infer units."
            },
            "dailyDrawdownCap": {
              "type": "object",
              "required": [
                "limit",
                "type",
                "window"
              ],
              "properties": {
                "limit": {
                  "type": "number",
                  "minimum": 0
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "percent",
                    "absolute"
                  ]
                },
                "window": {
                  "type": "string",
                  "description": "Duration string, canonical form '<integer>h' (e.g. '24h')."
                }
              }
            },
            "counterparty": {
              "type": "object",
              "description": "AIP v0.8 \u2014 counterparty controls. See aip-v0.8-draft-1.md \u00a72.1.",
              "properties": {
                "allowList": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Closed list of permitted counterparties. Entries SHOULD be DIDs; raw rail-specific addresses accepted as fallback."
                },
                "blockList": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Closed list of denied counterparties. DID or address strings."
                },
                "requireIssuerClassIn": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "op_first_party",
                      "sovereign_self_attested",
                      "third_party_kyb",
                      "partner",
                      "peer_agent"
                    ]
                  },
                  "description": "Counterparty's OP-tracked issuer_class MUST be an element of this set. Set semantics, not a numeric tier."
                }
              }
            },
            "temporal": {
              "type": "object",
              "description": "AIP v0.8 \u2014 time-of-day window constraint beyond the credential's validUntil. See aip-v0.8-draft-1.md \u00a72.2.",
              "properties": {
                "allowedTimeWindows": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "start",
                      "end",
                      "timezone"
                    ],
                    "properties": {
                      "start": {
                        "type": "string",
                        "pattern": "^[0-2][0-9]:[0-5][0-9]$",
                        "description": "HH:MM 24-hour."
                      },
                      "end": {
                        "type": "string",
                        "pattern": "^[0-2][0-9]:[0-5][0-9]$",
                        "description": "HH:MM 24-hour."
                      },
                      "timezone": {
                        "type": "string",
                        "description": "IANA timezone name (e.g. 'UTC', 'America/New_York')."
                      },
                      "daysOfWeek": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "mon",
                            "tue",
                            "wed",
                            "thu",
                            "fri",
                            "sat",
                            "sun"
                          ]
                        },
                        "description": "Days the window applies. Defaults to all days when absent."
                      }
                    }
                  }
                }
              }
            },
            "geographic": {
              "type": "object",
              "description": "AIP v0.8 \u2014 jurisdictional constraints on counterparties. Requires counterparty attestation data carrying jurisdiction. See aip-v0.8-draft-1.md \u00a72.3.",
              "properties": {
                "blockedJurisdictions": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "description": "ISO 3166-1 alpha-2 country codes; counterparty MUST NOT belong to any. Fail-open if jurisdiction unknown."
                },
                "allowedJurisdictionsOnly": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "description": "ISO 3166-1 alpha-2 country codes; if present, counterparty MUST belong to one of these. Fail-closed if jurisdiction unknown."
                }
              }
            },
            "velocity": {
              "type": "object",
              "description": "AIP v0.8 \u2014 aggregate volume velocity caps. Stateful; SHOULD be enforced server-side or by a stateful embedded evaluator. Cap values are denominated by the sibling tradingMandate.unit field. See aip-v0.8-draft-1.md \u00a72.4.",
              "properties": {
                "dailyVolumeCap": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Maximum aggregate transacted volume in any 24h rolling window."
                },
                "monthlyVolumeCap": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Maximum aggregate transacted volume in any 30d rolling window."
                }
              }
            },
            "crossRailBudget": {
              "type": "object",
              "description": "v2.2 \u2014 one rolling-24h cross-rail budget (binding, fail-closed). Verifiers MUST deny when: the transfer asset has no rate in `rates`; no cross-rail spend counter can be established; the counter currency differs from `currency`; `window` is unsupported; or the projected total exceeds `amount`. Conversion MUST round up (budgets trip early, never late). Rates are attested by the principal at issuance; verifiers MUST NOT consult any external price source.",
              "properties": {
                "amount": {
                  "type": "string",
                  "pattern": "^\\d+(\\.\\d+)?$",
                  "description": "Budget ceiling as a decimal string, denominated in `currency`."
                },
                "currency": {
                  "type": "string",
                  "minLength": 1,
                  "description": "Budget denomination (e.g. \"USD\"). All comparisons happen in this unit."
                },
                "window": {
                  "type": "string",
                  "enum": [
                    "P1D"
                  ],
                  "description": "Accounting window. v2.2 verifiers support exactly P1D (rolling 24 hours)."
                },
                "rates": {
                  "type": "object",
                  "minProperties": 1,
                  "additionalProperties": {
                    "type": "string",
                    "pattern": "^\\d+(\\.\\d+)?$"
                  },
                  "description": "Principal-attested price of 1 whole unit of each spendable asset, in `currency`, as decimal strings (e.g. {\"USDC\":\"1\",\"sat\":\"0.0005\"}). An asset absent from this map cannot be scoped and MUST be denied."
                }
              },
              "required": [
                "amount",
                "currency",
                "window",
                "rates"
              ],
              "additionalProperties": false
            }
          },
          "dependencies": {
            "maxNotionalPerOrder": [
              "unit"
            ],
            "maxPosition": [
              "unit"
            ]
          }
        },
        "delegation": {
          "type": "object",
          "required": [
            "scope"
          ],
          "additionalProperties": false,
          "properties": {
            "scope": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "spending_limits": {
                  "type": "object",
                  "required": [
                    "per_rail"
                  ],
                  "additionalProperties": false,
                  "properties": {
                    "per_rail": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "per_transaction": {
                            "type": "object",
                            "required": [
                              "max_amount",
                              "currency"
                            ],
                            "additionalProperties": false,
                            "properties": {
                              "max_amount": {
                                "type": "string"
                              },
                              "currency": {
                                "type": "string"
                              }
                            }
                          },
                          "per_day": {
                            "type": "object",
                            "required": [
                              "max_amount",
                              "currency"
                            ],
                            "additionalProperties": false,
                            "properties": {
                              "max_amount": {
                                "type": "string"
                              },
                              "currency": {
                                "type": "string"
                              }
                            }
                          },
                          "per_asset": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "object",
                              "additionalProperties": false,
                              "properties": {
                                "per_transaction": {
                                  "type": "object",
                                  "required": [
                                    "max_amount",
                                    "currency"
                                  ],
                                  "additionalProperties": false,
                                  "properties": {
                                    "max_amount": {
                                      "type": "string"
                                    },
                                    "currency": {
                                      "type": "string"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "action_categories": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "counterparty_scope": {
                  "type": "object"
                },
                "time_window": {
                  "type": "object"
                }
              }
            },
            "attenuation": {
              "type": "object"
            },
            "parent_delegation": {
              "type": [
                "object",
                "null"
              ]
            },
            "delegation_metadata": {
              "type": "object"
            }
          }
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "authorizationLevel": {
                "const": "one-time"
              }
            },
            "required": [
              "authorizationLevel"
            ]
          },
          "then": {
            "properties": {
              "authorizationConfig": {
                "required": [
                  "oneTime"
                ],
                "properties": {
                  "recurring": false,
                  "policy": false
                }
              }
            },
            "required": [
              "authorizationConfig"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "authorizationLevel": {
                "const": "recurring"
              }
            },
            "required": [
              "authorizationLevel"
            ]
          },
          "then": {
            "properties": {
              "authorizationConfig": {
                "required": [
                  "recurring"
                ],
                "properties": {
                  "oneTime": false,
                  "policy": false
                }
              }
            },
            "required": [
              "authorizationConfig"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "authorizationLevel": {
                "const": "policy"
              }
            },
            "required": [
              "authorizationLevel"
            ]
          },
          "then": {
            "properties": {
              "authorizationConfig": {
                "required": [
                  "policy"
                ],
                "properties": {
                  "oneTime": false,
                  "recurring": false
                }
              }
            },
            "required": [
              "authorizationConfig"
            ]
          }
        }
      ]
    },
    "credentialSchema": {
      "type": "object",
      "required": [
        "id",
        "type"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^https://observerprotocol.org/schemas/"
        },
        "type": {
          "const": "JsonSchema"
        }
      }
    },
    "credentialStatus": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "type",
          "statusPurpose",
          "statusListIndex",
          "statusListCredential"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uri"
          },
          "type": {
            "type": "string",
            "const": "BitstringStatusListEntry"
          },
          "statusPurpose": {
            "type": "string",
            "enum": [
              "revocation",
              "suspension"
            ]
          },
          "statusListIndex": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "statusListCredential": {
            "type": "string",
            "format": "uri"
          }
        },
        "additionalProperties": false
      }
    },
    "proof": {
      "type": "object",
      "description": "W3C VC Data Integrity proof describing the suite OP actually issues since the 2026-06-05 migration: DataIntegrityProof with cryptosuite eddsa-jcs-2022, proofValue as base58btc multibase (z-prefixed). The v2.1/v2.3 lineage carried the legacy Ed25519Signature2020/2026 proof shape unexamined; that suite is rejected by the OP verifier and is corrected here. proof is left open (no additionalProperties:false) to admit standard DI proof options (e.g. expires, domain).",
      "required": [
        "type",
        "cryptosuite",
        "created",
        "verificationMethod",
        "proofPurpose",
        "proofValue"
      ],
      "properties": {
        "type": {
          "const": "DataIntegrityProof"
        },
        "cryptosuite": {
          "const": "eddsa-jcs-2022"
        },
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "verificationMethod": {
          "type": "string",
          "pattern": "^did:[a-z]+:.+#.+"
        },
        "proofPurpose": {
          "const": "assertionMethod"
        },
        "proofValue": {
          "type": "string",
          "pattern": "^z[1-9A-HJ-NP-Za-km-z]+$"
        }
      }
    }
  },
  "additionalProperties": false
}