{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://moltspay.com/schemas/services.json",
  "title": "MoltsPay Services Manifest",
  "description": "Configuration file for MoltsPay x402 service providers",
  "type": "object",
  "required": ["provider", "services"],
  "properties": {
    "provider": {
      "type": "object",
      "description": "Service provider information",
      "required": ["name", "wallet"],
      "properties": {
        "name": {
          "type": "string",
          "description": "Provider display name",
          "examples": ["Zen7 Video Generation"]
        },
        "description": {
          "type": "string",
          "description": "Provider description"
        },
        "wallet": {
          "type": "string",
          "pattern": "^0x[a-fA-F0-9]{40}$",
          "description": "EVM address to receive payments (Base, Polygon, BNB, etc.)"
        },
        "solana_wallet": {
          "type": "string",
          "pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$",
          "description": "Solana address to receive payments (solana, solana_devnet)"
        },
        "chain": {
          "type": "string",
          "enum": ["base", "polygon", "base_sepolia", "tempo_moderato", "bnb", "bnb_testnet", "solana", "solana_devnet", "alipay", "wechat", "balance"],
          "default": "base",
          "description": "Single chain mode (use 'chains' for multi-chain). 'alipay'/'wechat' are fiat rails (2.0+/2.1+), 'balance' is the custodial rail (2.2+), none are blockchains."
        },
        "chains": {
          "type": "array",
          "description": "Supported chains/rails. EVM chains use 'wallet', Solana chains use 'solana_wallet', 'alipay' (2.0+) uses 'provider.alipay', 'wechat' (2.1+) uses 'provider.wechat'.",
          "items": {
            "type": "string",
            "enum": ["base", "polygon", "base_sepolia", "tempo_moderato", "bnb", "bnb_testnet", "solana", "solana_devnet", "alipay", "wechat", "balance"]
          },
          "examples": [
            ["base", "polygon", "solana_devnet"],
            ["base", "base_sepolia", "solana", "solana_devnet"],
            ["base", "polygon", "alipay"]
          ]
        },
        "alipay": {
          "type": "object",
          "description": "Alipay AI 收 provider config (2.0+). Required when 'chains' contains 'alipay'.",
          "required": ["seller_id", "app_id", "seller_name", "service_id_default", "private_key_path", "alipay_public_key_path"],
          "properties": {
            "seller_id": {
              "type": "string",
              "pattern": "^[0-9]{16}$",
              "description": "Merchant Alipay ID (16 digits)"
            },
            "app_id": {
              "type": "string",
              "pattern": "^[0-9]{16}$",
              "description": "Application ID from Alipay Open Platform"
            },
            "seller_name": {
              "type": "string",
              "description": "Merchant legal name (shown in 'method.seller_name' of the 402 challenge)"
            },
            "service_id_default": {
              "type": "string",
              "description": "Default service_id when a service entry doesn't override it (e.g. 'API_XXXXXXXXXXXXXXXX')"
            },
            "private_key_path": {
              "type": "string",
              "description": "Path to the RSA2 merchant private key PEM file (relative to moltspay.services.json)"
            },
            "alipay_public_key_path": {
              "type": "string",
              "description": "Path to the Alipay platform public key PEM file (relative to moltspay.services.json)"
            },
            "gateway_url": {
              "type": "string",
              "format": "uri",
              "default": "https://openapi.alipay.com/gateway.do",
              "description": "Open API gateway URL (use 'https://openapi.alipaydev.com/gateway.do' for sandbox)"
            },
            "sign_type": {
              "type": "string",
              "enum": ["RSA2"],
              "default": "RSA2",
              "description": "Signature algorithm. Only RSA2 is supported in 2.0."
            }
          }
        },
        "wechat": {
          "type": "object",
          "description": "WeChat Pay v3 Native provider config (2.1+). Required when 'chains' contains 'wechat'.",
          "required": ["mchid", "appid", "serial_no", "private_key_path", "notify_url"],
          "properties": {
            "mchid": {
              "type": "string",
              "description": "Merchant id (商户号)"
            },
            "appid": {
              "type": "string",
              "description": "App id (official account / mini-program / app)"
            },
            "serial_no": {
              "type": "string",
              "description": "Merchant API certificate serial number"
            },
            "private_key_path": {
              "type": "string",
              "description": "Path to the merchant RSA private key PEM file (relative to moltspay.services.json)"
            },
            "platform_public_key_path": {
              "type": "string",
              "description": "Path to the WeChat platform certificate public key PEM (enables response verification)"
            },
            "apiv3_key": {
              "type": "string",
              "minLength": 32,
              "maxLength": 32,
              "description": "APIv3 key (32 bytes). Only needed for callback decryption (Phase 2)"
            },
            "notify_url": {
              "type": "string",
              "format": "uri",
              "description": "Async result notify URL. Required by Native order create even when polling."
            },
            "api_base": {
              "type": "string",
              "format": "uri",
              "default": "https://api.mch.weixin.qq.com",
              "description": "Open API base URL"
            }
          }
        },
        "balance": {
          "type": "object",
          "description": "Custodial balance rail config (2.2+). Required when 'chains' contains 'balance'. Enabling requires Node.js >= 22.5.",
          "required": ["db_path"],
          "properties": {
            "db_path": {
              "type": "string",
              "description": "SQLite ledger file path (relative to moltspay.services.json); created on first start"
            },
            "currency": {
              "type": "string",
              "enum": ["USD", "CNY"],
              "default": "USD",
              "description": "Ledger quote currency. Recorded once and enforced on reopen (a mismatch refuses to start). CNY funds 1:1 from WeChat (payer_total is fen)."
            },
            "single_limit": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,2})?$",
              "default": "5.00",
              "description": "Default per-transaction limit for new buyers (decimal string, ledger currency)"
            },
            "daily_limit": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,2})?$",
              "default": "10.00",
              "description": "Default daily limit for new buyers (decimal string, ledger currency)"
            },
            "topup_packs": {
              "type": "array",
              "minItems": 1,
              "items": { "type": "string", "pattern": "^\\d+(\\.\\d{1,2})?$" },
              "description": "Offered recharge amounts in ledger currency (2.3+), e.g. [\"20.00\", \"50.00\"]"
            },
            "default_pack": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,2})?$",
              "description": "Pack the client auto-selects when a 402 finds an insufficient balance (2.3+). Must be one of topup_packs."
            },
            "auto_topup_max": {
              "type": "string",
              "pattern": "^\\d+(\\.\\d{1,2})?$",
              "description": "Ceiling on client auto-topup without explicit pack selection (2.3+). Must be >= the largest topup_pack."
            },
            "auth_mode": {
              "type": "string",
              "enum": ["off", "shadow", "enforce"],
              "default": "off",
              "description": "Balance spend authentication (2.4+). 'off': signature not checked (default, backward-compatible; buyer_id keeps bearer semantics). 'shadow': verify per-request signatures and log what would be denied, without blocking (use to confirm every client signs before tightening). 'enforce': reject unsigned/invalid/wrong-signer deductions with 401. The account's signer address is TOFU-bound on first signed use and anchored to the WeChat payer openid at top-up."
            }
          }
        }
      }
    },
    "services": {
      "type": "array",
      "description": "List of available services",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["id", "price", "currency"],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z0-9-]+$",
            "description": "Unique service identifier",
            "examples": ["text-to-video", "image-to-video"]
          },
          "name": { "type": "string", "description": "Human-readable service name" },
          "description": { "type": "string", "description": "Service description" },
          "function": {
            "type": "string",
            "pattern": "^[a-zA-Z][a-zA-Z0-9]*$",
            "description": "Function name exported from index.js"
          },
          "price": { "type": "number", "minimum": 0, "description": "Price in currency units" },
          "currency": { "type": "string", "enum": ["USDC", "USDT"], "default": "USDC" },
          "input": { "type": "object", "description": "Input parameters schema" },
          "output": { "type": "object", "description": "Output schema" },
          "alipay": {
            "type": "object",
            "description": "Alipay AI 收 per-service config (2.0+). Set when this service accepts CNY payments.",
            "required": ["price_cny", "goods_name"],
            "properties": {
              "service_id": {
                "type": "string",
                "description": "Per-service service_id (defaults to provider.alipay.service_id_default)"
              },
              "price_cny": {
                "type": "string",
                "pattern": "^\\d+(\\.\\d{1,2})?$",
                "description": "CNY price as decimal string in 元 (e.g. '7.00' = 7 CNY, NOT cents)"
              },
              "goods_name": {
                "type": "string",
                "description": "Goods name shown to the user in the Alipay app"
              }
            }
          },
          "wechat": {
            "type": "object",
            "description": "WeChat Pay Native per-service config (2.1+). Set when this service accepts CNY payments.",
            "required": ["price_cny", "description"],
            "properties": {
              "price_cny": {
                "type": "string",
                "pattern": "^\\d+(\\.\\d{1,2})?$",
                "description": "CNY price as decimal string in yuan (e.g. '10.00' = 10 CNY, NOT fen)"
              },
              "description": {
                "type": "string",
                "description": "Order description shown to the payer in the WeChat app"
              }
            }
          }
        }
      }
    }
  },
  "examples": [
    {
      "provider": {
        "name": "Zen7 Video Generation",
        "wallet": "0xb8d6f2441e8f8dfB6288A74Cf73804cDd0484E0C",
        "solana_wallet": "CNbgcwV95JCguguA652kxwXPhS6EwoskeBPH45o8ow7K",
        "chains": ["base", "base_sepolia", "polygon", "solana_devnet"]
      },
      "services": [
        { "id": "text-to-video", "function": "textToVideo", "price": 0.99, "currency": "USDC" }
      ]
    },
    {
      "provider": {
        "name": "My Shop",
        "wallet": "0x0000000000000000000000000000000000000000",
        "chains": ["base", "polygon", "alipay"],
        "alipay": {
          "seller_id": "2088000000000000",
          "app_id": "2021000000000000",
          "seller_name": "Example Merchant Co., Ltd.",
          "service_id_default": "API_XXXXXXXXXXXXXXXX",
          "private_key_path": "./cert/ALIPAY_PRIVATE_KEY.txt",
          "alipay_public_key_path": "./cert/ALIPAY_PUBLIC_KEY.txt"
        }
      },
      "services": [
        {
          "id": "text-to-video",
          "function": "textToVideo",
          "price": 0.99,
          "currency": "USDC",
          "alipay": {
            "service_id": "API_XXXXXXXXXXXXXXXX",
            "price_cny": "7.00",
            "goods_name": "Demo Video"
          }
        }
      ]
    }
  ]
}
