{
  "service": "Guardrail — Spend Policy Check",
  "description": "Evaluates a proposed agent payment against spending policy and returns an allow, deny, or escalate decision, with the rule that produced it.",
  "version": "1.0.0",
  "outputSchema": {
    "input": {
      "type": "http",
      "method": "POST",
      "path": "/",
      "bodyType": "json",
      "body": {
        "type": "object",
        "required": [
          "amount_micros",
          "merchant",
          "job_budget_micros",
          "per_tx_limit_micros",
          "daily_cap_micros",
          "approval_above_micros"
        ],
        "properties": {
          "amount_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Proposed payment, int64 micro-USDC (6dp). Send as a string above 2^53-1."
          },
          "merchant": {
            "type": "string",
            "description": "Merchant host — what the allowlist matches."
          },
          "job_budget_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Total job operating budget. Zero/absent denies."
          },
          "job_committed_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Already committed against the job. Defaults 0."
          },
          "daily_cap_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Daily cumulative cap. Zero/absent denies."
          },
          "daily_spent_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Already spent in the current window. Defaults 0. The window is the CALLER contract — the UTC calendar day."
          },
          "per_tx_limit_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Per-transaction hard limit. Zero/absent denies."
          },
          "approval_above_micros": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Above this, a human must approve. Zero/absent escalates everything."
          },
          "merchant_allowlist": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "OPTIONAL. Supplied -> rule runs fail-closed. Omitted -> rule is SKIPPED and reported NOT_EVALUATED."
          },
          "merchant_categories": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "OPTIONAL. Merchant -> category. An unmapped merchant passes."
          },
          "blocked_categories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "OPTIONAL. Categories to block. Needs merchant_categories to run."
          },
          "kind": {
            "type": "string",
            "description": "OPTIONAL. Only \"payment\" (or absent) is modelled; anything else denies."
          }
        }
      }
    }
  },
  "rules": [
    "intent-validation",
    "job-budget",
    "per-tx-limit",
    "daily-cap",
    "merchant-allowlist (optional)",
    "blocked-category (optional)",
    "approval-threshold"
  ],
  "notes": [
    "Rules are evaluated in a fixed short-circuit order; the first failure wins.",
    "Unset never means unlimited: a zero or absent limit denies (or escalates, at the threshold).",
    "All amounts are int64 micro-USDC. No floats touch money.",
    "A rule that did not run is reported NOT_EVALUATED, never PASS."
  ]
}