SKU#19 · ruleset mandate-scope-v1

Mandate scope

Verificación informativa de un Intent Mandate v0.1.0 (producto canónico Mandato AR) contra un spend propuesto (resource + price). Son reglas explícitas: scope ≠ create/sign. Este SKU no crea ni firma mandatos; solo verifica allowlist, presupuesto, vencimiento y firma.

Endpoint

GET /api/mandate/scope — x402 v2 Exact, $0.02 USDC en Base (eip155:8453, amount atómico 20000). Sin pago responde HTTP 402 + PAYMENT-REQUIRED. Query ausente o inválida responde 400 { error, hint } antes del cobro. Checks fallidos tras pagar siguen en HTTP 200 con ok:false (no se re-402).

Canonical smoke curl (unpaid → HTTP 402 amount 20000; HMAC demo mandate-scope-v1-demo; deploy 5ef4055b / merge 356c4cd0):

curl -i 'https://lupariel.com/api/mandate/scope?resource=https%3A%2F%2Flupariel.com%2Fapi%2Fsettle%2Freceipt&price_usdc=0.02&mandate=eyJ2ZXJzaW9uIjoiMC4xLjAiLCJwcmluY2lwYWwiOiJkaWQ6ZXhhbXBsZTpjb21wcmFzLXNtb2tlIiwiYnVkZ2V0VXNkYyI6IjAuMDUiLCJleHBpcmVzQXQiOiIyMDI3LTEyLTMxVDIzOjU5OjU5LjAwMFoiLCJhbGxvd2xpc3QiOlsiaHR0cHM6Ly9sdXBhcmllbC5jb20vYXBpL3NldHRsZS9yZWNlaXB0KiIsImh0dHBzOi8vbHVwYXJpZWwuY29tL2FwaS9tYW5kYXRlL3Njb3BlKiJdLCJuZXR3b3JrIjoiZWlwMTU1Ojg0NTMiLCJyZXNvdXJjZUJhc2UiOiJodHRwczovL2x1cGFyaWVsLmNvbSIsIm5vbmNlIjoic21va2UxOS01MWZkNzY5ODNjNDczNmU4Iiwic2lnbmF0dXJlIjoiaG1hYzpmY2RkMmNkNDRmY2VjOTNjYWMyYzM4YzI1Y2FkMWJiOWZkZDM0ZGVkZTdlYjE1OTFhYTdlNjI5MWQyZGEzNGUyIn0'

Lookup sigue en /api/lookup. Settle-receipt sigue en /api/settle/receipt. HTML y /rieles.json no cambian.

Query

  • resource (requerido): URL http(s) absoluta del spend propuesto.
  • price_usdc (requerido): decimal USDC (ej. 0.02).
  • mandate (requerido): JSON Intent Mandate v0.1.0 en base64url (schema mandato-ar packages/mandate).
  • spent_usdc (opcional, default 0): ya gastado, para remaining/budget.
  • pubkey (opcional; requerido si signature es ed25519:): clave pública hex.
  • lang (opcional, es|en).

Checks

  • schemaValid — Intent Mandate v0.1.0.
  • signatureValid — hmac: con secret demo mandate-scope-v1-demo (smoke); ed25519: + pubkey.
  • notExpired — expiresAt > now.
  • networkMatch — mandate.network === eip155:8453 (solo Base).
  • resourceAllowed — isUrlAllowed(resource, allowlist).
  • budgetSufficient — budget − spent ≥ price.

ok es true solo si los seis checks son true.

Respuesta 200 (post-pago)

{
  "product": "Mandato AR",
  "kind": "mandate-scope",
  "ruleset": "mandate-scope-v1",
  "ok": true,
  "checks": {
    "schemaValid": true,
    "signatureValid": true,
    "notExpired": true,
    "networkMatch": true,
    "resourceAllowed": true,
    "budgetSufficient": true
  },
  "constraints": {
    "version": "0.1.0",
    "principal": "did:example:compras-smoke",
    "network": "eip155:8453",
    "resourceBase": "https://lupariel.com",
    "allowlist": [
      "https://lupariel.com/api/settle/receipt*",
      "https://lupariel.com/api/mandate/scope*"
    ],
    "budgetUsdc": "0.05",
    "remainingUsdc": "0.05",
    "expiresAt": "2027-12-31T23:59:59.000Z"
  },
  "resource": "https://lupariel.com/api/settle/receipt",
  "priceUsdc": "0.02",
  "scope_vs_create": {
    "scope": "server verify allowlist+budget+expiry+signature against a proposed spend",
    "create": "local createSignedMandate/signMandate — NOT this endpoint"
  },
  "disclaimer": "Does not create or sign a mandate. Verifies Intent Mandate v0.1.0 scope/constraints only.",
  "attested_at": "2026-09-23T00:00:00.000Z",
  "lang": "es"
}

Qué no es

  • No crea ni firma un mandato (eso es local en Mandato AR).
  • No es settle-receipt, settle-ready ni consent-hop.
  • No acepta Polygon: solo Base eip155:8453.
  • No reemplaza a /api/lookup, rail-matrix ni liveness.

Discovery: /openapi.json y /.well-known/x402. Facilitator por defecto: PayAI (https://facilitator.payai.network).