{
  "schemaVersion": "1.0",
  "item": {
    "slug": "aperture",
    "name": "aperture: the L402 aware reverse proxy",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/Roasbeef/aperture",
    "canonicalUrl": "https://clawhub.ai/Roasbeef/aperture",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/aperture",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=aperture",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "templates/docker-compose-aperture.yml",
      "templates/aperture-regtest.yaml",
      "templates/aperture-example.yaml",
      "scripts/setup.sh",
      "scripts/install.sh"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/aperture"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/aperture",
    "agentPageUrl": "https://openagent3.xyz/skills/aperture/agent",
    "manifestUrl": "https://openagent3.xyz/skills/aperture/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/aperture/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Aperture - L402 Lightning Reverse Proxy",
        "body": "Aperture is a reverse proxy that implements the L402 protocol, enabling\npayment-gated API access via the Lightning Network. It sits in front of your\nbackend services and requires Lightning micropayments before granting access.\n\nSource: github.com/lightninglabs/aperture"
      },
      {
        "title": "Quick Start",
        "body": "# 1. Install aperture\nskills/aperture/scripts/install.sh\n\n# 2. Generate config (connects to local lnd)\nskills/aperture/scripts/setup.sh\n\n# 3. Ensure invoice.macaroon exists (required for L402 invoice creation)\n#    If not present, bake one with the macaroon-bakery skill:\nskills/macaroon-bakery/scripts/bake.sh --role invoice-only \\\n    --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon\n\n# 4. Start aperture\nskills/aperture/scripts/start.sh\n\n# 5. Test with lnget\nlnget -k --no-pay https://localhost:8081/api/test"
      },
      {
        "title": "How Aperture Works",
        "body": "Client requests a protected resource through Aperture\nAperture responds with HTTP 402 + WWW-Authenticate: L402 header containing\na macaroon and a Lightning invoice\nClient pays the invoice and obtains the preimage\nClient retries with Authorization: L402 <macaroon>:<preimage>\nAperture validates the token and proxies to the backend service"
      },
      {
        "title": "Installation",
        "body": "skills/aperture/scripts/install.sh\n\nThis will:\n\nVerify Go is installed\nRun go install github.com/lightninglabs/aperture/cmd/aperture@latest\nVerify aperture is on $PATH\n\nTo install manually:\n\ngo install github.com/lightninglabs/aperture/cmd/aperture@latest\n\nOr build from source:\n\ngit clone https://github.com/lightninglabs/aperture.git\ncd aperture\nmake install"
      },
      {
        "title": "Setup",
        "body": "skills/aperture/scripts/setup.sh\n\nThis generates ~/.aperture/aperture.yaml from the config template with\nsensible defaults. The setup script auto-detects the local lnd node paths.\n\nOptions:\n\n# Custom network\nsetup.sh --network testnet\n\n# Custom lnd paths\nsetup.sh --lnd-host localhost:10009 \\\n         --lnd-tls ~/.lnd/tls.cert \\\n         --lnd-macdir ~/.lnd/data/chain/bitcoin/mainnet\n\n# Custom listen port\nsetup.sh --port 8081\n\n# Disable TLS (development only)\nsetup.sh --insecure\n\n# Disable auth (no payments required)\nsetup.sh --no-auth"
      },
      {
        "title": "Start",
        "body": "skills/aperture/scripts/start.sh\n\nStarts aperture as a background process reading ~/.aperture/aperture.yaml.\n\nOptions:\n\nstart.sh --foreground         # Run in foreground\nstart.sh --config /path/to   # Custom config path"
      },
      {
        "title": "Stop",
        "body": "skills/aperture/scripts/stop.sh"
      },
      {
        "title": "Configuration",
        "body": "Config file: ~/.aperture/aperture.yaml"
      },
      {
        "title": "Invoice Macaroon Requirement",
        "body": "Aperture requires invoice.macaroon in the configured macdir to create\nLightning invoices for L402 challenges. This is not the same as\nadmin.macaroon. If the macaroon is missing, aperture will fail to start or\nwill return errors when clients request paid resources.\n\nTo bake an invoice macaroon with the macaroon-bakery skill:\n\nskills/macaroon-bakery/scripts/bake.sh --role invoice-only \\\n    --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon\n\nThe setup.sh script will warn you if invoice.macaroon is not found at the\nexpected path."
      },
      {
        "title": "Minimal Agent Configuration",
        "body": "This is the minimal config for an agent hosting paid endpoints with a local\nlnd node:\n\nlistenaddr: \"localhost:8081\"\ninsecure: true\ndebuglevel: \"info\"\ndbbackend: \"sqlite\"\nsqlite:\n  dbfile: \"~/.aperture/aperture.db\"\n\nauthenticator:\n  network: \"mainnet\"\n  lndhost: \"localhost:10009\"\n  tlspath: \"~/.lnd/tls.cert\"\n  macdir: \"~/.lnd/data/chain/bitcoin/mainnet\"\n\nservices:\n  - name: \"my-api\"\n    hostregexp: \".*\"\n    pathregexp: \"^/api/.*$\"\n    address: \"127.0.0.1:8080\"\n    protocol: http\n    price: 100"
      },
      {
        "title": "Service Configuration",
        "body": "Each service entry defines a backend to protect:\n\nservices:\n  - name: \"service-name\"\n    # Match requests by host (regex).\n    hostregexp: \"^api.example.com$\"\n\n    # Match requests by path (regex).\n    pathregexp: \"^/paid/.*$\"\n\n    # Backend address to proxy to.\n    address: \"127.0.0.1:8080\"\n\n    # Protocol: http or https.\n    protocol: http\n\n    # Static price in satoshis.\n    price: 100\n\n    # Macaroon capabilities granted at base tier.\n    capabilities: \"read,write\"\n\n    # Token expiry in seconds (31557600 = 1 year).\n    timeout: 31557600\n\n    # Paths exempt from payment.\n    authwhitelistpaths:\n      - \"^/health$\"\n      - \"^/public/.*$\"\n\n    # Per-endpoint rate limits (token bucket).\n    ratelimits:\n      - pathregexp: \"^/api/query.*$\"\n        requests: 10\n        per: 1s\n        burst: 20"
      },
      {
        "title": "Authentication Backends",
        "body": "Direct LND Connection\n\nauthenticator:\n  network: \"mainnet\"\n  lndhost: \"localhost:10009\"\n  tlspath: \"~/.lnd/tls.cert\"\n  macdir: \"~/.lnd/data/chain/bitcoin/mainnet\"\n\nLightning Node Connect (LNC)\n\nauthenticator:\n  network: \"mainnet\"\n  passphrase: \"your-pairing-phrase\"\n  mailboxaddress: \"mailbox.terminal.lightning.today:443\"\n\nDisable Authentication\n\nauthenticator:\n  disable: true"
      },
      {
        "title": "Database Backends",
        "body": "SQLite (recommended for agents):\n\ndbbackend: \"sqlite\"\nsqlite:\n  dbfile: \"~/.aperture/aperture.db\"\n\nPostgreSQL:\n\ndbbackend: \"postgres\"\npostgres:\n  host: \"localhost\"\n  port: 5432\n  user: \"aperture\"\n  password: \"secret\"\n  dbname: \"aperture\""
      },
      {
        "title": "TLS Configuration",
        "body": "# Auto Let's Encrypt certificate.\nautocert: true\nservername: \"api.example.com\"\n\n# Or disable TLS (development/local only).\ninsecure: true\n\nIf neither is set, Aperture generates self-signed certs in ~/.aperture/."
      },
      {
        "title": "Dynamic Pricing",
        "body": "Connect to a gRPC price server instead of static prices:\n\nservices:\n  - name: \"my-api\"\n    dynamicprice:\n      enabled: true\n      grpcaddress: \"127.0.0.1:10010\"\n      insecure: false\n      tlscertpath: \"/path/to/pricer/tls.cert\""
      },
      {
        "title": "Hosting Paid Content for Agents",
        "body": "A common pattern is hosting information that other agents pay to access:\n\n# 1. Start a simple HTTP backend with your content\nmkdir -p /tmp/paid-content\necho '{\"data\": \"valuable information\"}' > /tmp/paid-content/info.json\ncd /tmp/paid-content && python3 -m http.server 8080 &\n\n# 2. Configure aperture to protect it\nskills/aperture/scripts/setup.sh --insecure --port 8081\n\n# 3. Start aperture\nskills/aperture/scripts/start.sh\n\n# 4. Other agents can now pay and fetch\nlnget --max-cost 100 https://localhost:8081/api/info.json"
      },
      {
        "title": "Integration with lnget and lnd",
        "body": "With all three components running:\n\n# Verify lnd is running\nskills/lnd/scripts/lncli.sh getinfo\n\n# Start aperture (uses same lnd for invoice generation)\nskills/aperture/scripts/start.sh\n\n# Fetch a paid resource\nlnget --max-cost 1000 https://localhost:8081/api/data\n\n# Check tokens\nlnget tokens list"
      },
      {
        "title": "File Locations",
        "body": "PathPurpose~/.aperture/aperture.yamlConfiguration file~/.aperture/aperture.dbSQLite database~/.aperture/tls.certTLS certificate~/.aperture/tls.keyTLS private key~/.aperture/aperture.logLog file"
      },
      {
        "title": "Port already in use",
        "body": "Change listenaddr in config to a different port, or use setup.sh --port."
      },
      {
        "title": "LND connection refused",
        "body": "Verify lnd is running and wallet is unlocked. Check lndhost, tlspath, and\nmacdir in the config point to the correct lnd instance."
      },
      {
        "title": "No 402 challenge returned",
        "body": "Check that the request path matches a service's pathregexp and is not in\nauthwhitelistpaths. Verify authenticator.disable is not true."
      },
      {
        "title": "Token validation fails",
        "body": "The client must present the exact macaroon from the challenge with the correct\npreimage. Verify the preimage matches the payment hash."
      }
    ],
    "body": "Aperture - L402 Lightning Reverse Proxy\n\nAperture is a reverse proxy that implements the L402 protocol, enabling payment-gated API access via the Lightning Network. It sits in front of your backend services and requires Lightning micropayments before granting access.\n\nSource: github.com/lightninglabs/aperture\n\nQuick Start\n# 1. Install aperture\nskills/aperture/scripts/install.sh\n\n# 2. Generate config (connects to local lnd)\nskills/aperture/scripts/setup.sh\n\n# 3. Ensure invoice.macaroon exists (required for L402 invoice creation)\n#    If not present, bake one with the macaroon-bakery skill:\nskills/macaroon-bakery/scripts/bake.sh --role invoice-only \\\n    --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon\n\n# 4. Start aperture\nskills/aperture/scripts/start.sh\n\n# 5. Test with lnget\nlnget -k --no-pay https://localhost:8081/api/test\n\nHow Aperture Works\nClient requests a protected resource through Aperture\nAperture responds with HTTP 402 + WWW-Authenticate: L402 header containing a macaroon and a Lightning invoice\nClient pays the invoice and obtains the preimage\nClient retries with Authorization: L402 <macaroon>:<preimage>\nAperture validates the token and proxies to the backend service\nInstallation\nskills/aperture/scripts/install.sh\n\n\nThis will:\n\nVerify Go is installed\nRun go install github.com/lightninglabs/aperture/cmd/aperture@latest\nVerify aperture is on $PATH\n\nTo install manually:\n\ngo install github.com/lightninglabs/aperture/cmd/aperture@latest\n\n\nOr build from source:\n\ngit clone https://github.com/lightninglabs/aperture.git\ncd aperture\nmake install\n\nSetup\nskills/aperture/scripts/setup.sh\n\n\nThis generates ~/.aperture/aperture.yaml from the config template with sensible defaults. The setup script auto-detects the local lnd node paths.\n\nOptions:\n\n# Custom network\nsetup.sh --network testnet\n\n# Custom lnd paths\nsetup.sh --lnd-host localhost:10009 \\\n         --lnd-tls ~/.lnd/tls.cert \\\n         --lnd-macdir ~/.lnd/data/chain/bitcoin/mainnet\n\n# Custom listen port\nsetup.sh --port 8081\n\n# Disable TLS (development only)\nsetup.sh --insecure\n\n# Disable auth (no payments required)\nsetup.sh --no-auth\n\nRunning Aperture\nStart\nskills/aperture/scripts/start.sh\n\n\nStarts aperture as a background process reading ~/.aperture/aperture.yaml.\n\nOptions:\n\nstart.sh --foreground         # Run in foreground\nstart.sh --config /path/to   # Custom config path\n\nStop\nskills/aperture/scripts/stop.sh\n\nConfiguration\n\nConfig file: ~/.aperture/aperture.yaml\n\nInvoice Macaroon Requirement\n\nAperture requires invoice.macaroon in the configured macdir to create Lightning invoices for L402 challenges. This is not the same as admin.macaroon. If the macaroon is missing, aperture will fail to start or will return errors when clients request paid resources.\n\nTo bake an invoice macaroon with the macaroon-bakery skill:\n\nskills/macaroon-bakery/scripts/bake.sh --role invoice-only \\\n    --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon\n\n\nThe setup.sh script will warn you if invoice.macaroon is not found at the expected path.\n\nMinimal Agent Configuration\n\nThis is the minimal config for an agent hosting paid endpoints with a local lnd node:\n\nlistenaddr: \"localhost:8081\"\ninsecure: true\ndebuglevel: \"info\"\ndbbackend: \"sqlite\"\nsqlite:\n  dbfile: \"~/.aperture/aperture.db\"\n\nauthenticator:\n  network: \"mainnet\"\n  lndhost: \"localhost:10009\"\n  tlspath: \"~/.lnd/tls.cert\"\n  macdir: \"~/.lnd/data/chain/bitcoin/mainnet\"\n\nservices:\n  - name: \"my-api\"\n    hostregexp: \".*\"\n    pathregexp: \"^/api/.*$\"\n    address: \"127.0.0.1:8080\"\n    protocol: http\n    price: 100\n\nService Configuration\n\nEach service entry defines a backend to protect:\n\nservices:\n  - name: \"service-name\"\n    # Match requests by host (regex).\n    hostregexp: \"^api.example.com$\"\n\n    # Match requests by path (regex).\n    pathregexp: \"^/paid/.*$\"\n\n    # Backend address to proxy to.\n    address: \"127.0.0.1:8080\"\n\n    # Protocol: http or https.\n    protocol: http\n\n    # Static price in satoshis.\n    price: 100\n\n    # Macaroon capabilities granted at base tier.\n    capabilities: \"read,write\"\n\n    # Token expiry in seconds (31557600 = 1 year).\n    timeout: 31557600\n\n    # Paths exempt from payment.\n    authwhitelistpaths:\n      - \"^/health$\"\n      - \"^/public/.*$\"\n\n    # Per-endpoint rate limits (token bucket).\n    ratelimits:\n      - pathregexp: \"^/api/query.*$\"\n        requests: 10\n        per: 1s\n        burst: 20\n\nAuthentication Backends\nDirect LND Connection\nauthenticator:\n  network: \"mainnet\"\n  lndhost: \"localhost:10009\"\n  tlspath: \"~/.lnd/tls.cert\"\n  macdir: \"~/.lnd/data/chain/bitcoin/mainnet\"\n\nLightning Node Connect (LNC)\nauthenticator:\n  network: \"mainnet\"\n  passphrase: \"your-pairing-phrase\"\n  mailboxaddress: \"mailbox.terminal.lightning.today:443\"\n\nDisable Authentication\nauthenticator:\n  disable: true\n\nDatabase Backends\n\nSQLite (recommended for agents):\n\ndbbackend: \"sqlite\"\nsqlite:\n  dbfile: \"~/.aperture/aperture.db\"\n\n\nPostgreSQL:\n\ndbbackend: \"postgres\"\npostgres:\n  host: \"localhost\"\n  port: 5432\n  user: \"aperture\"\n  password: \"secret\"\n  dbname: \"aperture\"\n\nTLS Configuration\n# Auto Let's Encrypt certificate.\nautocert: true\nservername: \"api.example.com\"\n\n# Or disable TLS (development/local only).\ninsecure: true\n\n\nIf neither is set, Aperture generates self-signed certs in ~/.aperture/.\n\nDynamic Pricing\n\nConnect to a gRPC price server instead of static prices:\n\nservices:\n  - name: \"my-api\"\n    dynamicprice:\n      enabled: true\n      grpcaddress: \"127.0.0.1:10010\"\n      insecure: false\n      tlscertpath: \"/path/to/pricer/tls.cert\"\n\nHosting Paid Content for Agents\n\nA common pattern is hosting information that other agents pay to access:\n\n# 1. Start a simple HTTP backend with your content\nmkdir -p /tmp/paid-content\necho '{\"data\": \"valuable information\"}' > /tmp/paid-content/info.json\ncd /tmp/paid-content && python3 -m http.server 8080 &\n\n# 2. Configure aperture to protect it\nskills/aperture/scripts/setup.sh --insecure --port 8081\n\n# 3. Start aperture\nskills/aperture/scripts/start.sh\n\n# 4. Other agents can now pay and fetch\nlnget --max-cost 100 https://localhost:8081/api/info.json\n\nIntegration with lnget and lnd\n\nWith all three components running:\n\n# Verify lnd is running\nskills/lnd/scripts/lncli.sh getinfo\n\n# Start aperture (uses same lnd for invoice generation)\nskills/aperture/scripts/start.sh\n\n# Fetch a paid resource\nlnget --max-cost 1000 https://localhost:8081/api/data\n\n# Check tokens\nlnget tokens list\n\nFile Locations\nPath\tPurpose\n~/.aperture/aperture.yaml\tConfiguration file\n~/.aperture/aperture.db\tSQLite database\n~/.aperture/tls.cert\tTLS certificate\n~/.aperture/tls.key\tTLS private key\n~/.aperture/aperture.log\tLog file\nTroubleshooting\nPort already in use\n\nChange listenaddr in config to a different port, or use setup.sh --port.\n\nLND connection refused\n\nVerify lnd is running and wallet is unlocked. Check lndhost, tlspath, and macdir in the config point to the correct lnd instance.\n\nNo 402 challenge returned\n\nCheck that the request path matches a service's pathregexp and is not in authwhitelistpaths. Verify authenticator.disable is not true.\n\nToken validation fails\n\nThe client must present the exact macaroon from the challenge with the correct preimage. Verify the preimage matches the payment hash."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Roasbeef/aperture",
    "publisherUrl": "https://clawhub.ai/Roasbeef/aperture",
    "owner": "Roasbeef",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/aperture",
    "downloadUrl": "https://openagent3.xyz/downloads/aperture",
    "agentUrl": "https://openagent3.xyz/skills/aperture/agent",
    "manifestUrl": "https://openagent3.xyz/skills/aperture/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/aperture/agent.md"
  }
}