{
  "id": "lnqTOTUmd1cb2r7f",
  "name": "\ud83d\udcb2AgentGatePay - Seller Resource API [TEMPLATE]",
  "tags": [],
  "nodes": [
    {
      "id": "2a5eb6b5-b01e-43fb-adef-7cc5aa35c92c",
      "name": "\ud83d\udce1 GET /resource/{id}",
      "type": "n8n-nodes-base.webhook",
      "notes": "PUBLIC ENDPOINT\n\n\u2705 NO EDITS NEEDED\n\nCopy webhook URL after activating!",
      "position": [
        592,
        208
      ],
      "parameters": {
        "path": "resource/:resourceId",
        "options": {
          "rawBody": false
        },
        "responseMode": "responseNode"
      },
      "typeVersion": 1.1
    },
    {
      "id": "66292d2e-2752-48da-b970-bbb96cc87a5a",
      "name": "1\ufe0f\u20e3 Parse Request",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udd27 EDIT THIS NODE!\n\nReplace 2 values:\n1. wallet_address\n2. api_key",
      "position": [
        800,
        208
      ],
      "parameters": {
        "jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// \ud83d\udccb SELLER CONFIGURATION (EDIT THESE 2 VALUES!)\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst SELLER_CONFIG = {\n  merchant: {\n    name: \"DataBot Pro\",\n    company: \"MarketInsights AI Ltd.\",\n    email: \"user@example.com\",\n    \n    // YOUR BASE WALLET ADDRESS (where you receive USDC)\n    wallet_address: \"YOUR_WALLET_ADDRESS\",\n    \n    // YOUR AGENTGATEPAY API KEY\n    api_key: \"YOUR AGENTGATEPAY API KEY\"\n  },\n  \n  payment: {\n    token: \"USDC\",\n    chain: \"base\"\n  },\n  \n  catalog: {\n    \"saas-competitors-2025\": {\n      id: \"saas-competitors-2025\",\n      title: \"Top 5 SaaS Competitors Analysis 2025\",\n      price_usd: 0.01,\n      preview: \"Salesforce (19.8%), HubSpot (8.5%), Zendesk (6.2%)...\"\n    }\n  }\n};\n\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// VALIDATION (DO NOT EDIT)\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst errors = [];\n\nif (SELLER_CONFIG.merchant.wallet_address === \"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbB\") {\n  errors.push(\"\u274c wallet_address not configured\");\n}\n\nif (SELLER_CONFIG.merchant.api_key === \"YOUR_AGENTPAY_API_KEY\") {\n  errors.push(\"\u274c api_key not configured\");\n}\n\nif (errors.length > 0) {\n  return [{\n    json: {\n      route: \"error_config\",\n      http_response: {\n        statusCode: 500,\n        message: \"Seller configuration incomplete\",\n        errors: errors\n      }\n    }\n  }];\n}\n\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// PARSE REQUEST (DO NOT EDIT)\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst request = $input.first().json;\nconst resource_id = request.params?.resourceId || request.query?.resourceId;\nconst headers = request.headers || {};\n\nconst payment_tx_hash = headers['x-payment'] || headers['X-Payment'];\nconst agent_id = headers['x-agent-id'] || headers['X-Agent-Id'];\n\nconst resource = SELLER_CONFIG.catalog[resource_id];\n\nif (!resource) {\n  return [{\n    json: {\n      route: \"error_404\",\n      http_response: {\n        statusCode: 404,\n        message: \"Resource not found\",\n        resource_id: resource_id,\n        available: Object.keys(SELLER_CONFIG.catalog)\n      }\n    }\n  }];\n}\n\nreturn [{\n  json: {\n    config: SELLER_CONFIG,\n    resource: resource,\n    request: {\n      resource_id: resource_id,\n      agent_id: agent_id,\n      payment_tx_hash: payment_tx_hash,\n      has_payment: !!payment_tx_hash\n    },\n    route: payment_tx_hash ? \"verify_payment\" : \"return_402\"\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "256e6d34-a4d0-4d0b-9b0a-427b29a9ddb6",
      "name": "2\ufe0f\u20e3 Has Payment?",
      "type": "n8n-nodes-base.if",
      "notes": "\u2705 NO EDITS NEEDED",
      "position": [
        992,
        208
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "has-payment",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.route }}",
              "rightValue": "verify_payment"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "aa1acd74-3c89-4efc-96a3-e5a335a0f868",
      "name": "3\ufe0f\u20e3 Generate 402",
      "type": "n8n-nodes-base.code",
      "notes": "\u2705 NO EDITS NEEDED",
      "position": [
        1200,
        32
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst config = data.config;\nconst resource = data.resource;\n\nconst token_decimals = config.payment.token === \"DAI\" ? 18 : 6;\nconst amount = Math.floor(resource.price_usd * Math.pow(10, token_decimals));\nconst nonce = `nonce_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\nconst response_402 = {\n  statusCode: 402,\n  message: \"Payment Required\",\n  protocol: \"x402\",\n  \n  payTo: config.merchant.wallet_address,\n  amount: amount.toString(),\n  token: config.payment.token,\n  chain: config.payment.chain,\n  priceUsd: resource.price_usd.toString(),\n  nonce: nonce,\n  \n  resource: {\n    id: resource.id,\n    title: resource.title,\n    preview: resource.preview\n  },\n  \n  merchant: {\n    name: config.merchant.name,\n    email: config.merchant.email\n  },\n  \n  instructions: [\n    `1. Send ${amount} ${config.payment.token} to ${config.merchant.wallet_address}`,\n    `2. Wait for confirmation`,\n    `3. Retry with header: x-payment: {tx_hash}`\n  ]\n};\n\nreturn [{\n  json: {\n    http_response: response_402\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "cb658f93-2039-4182-bec1-ac3214991bc7",
      "name": "4\ufe0f\u20e3 Send 402",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "\u2705 NO EDITS NEEDED",
      "position": [
        1408,
        32
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json.http_response) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "69e40d79-e0c8-473f-8fc4-87d20ad63071",
      "name": "5\ufe0f\u20e3 Verify Payment",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\u2705 NO EDITS NEEDED",
      "position": [
        1200,
        304
      ],
      "parameters": {
        "url": "=https://api.agentgatepay.com/v1/payments/verify/{{ $('1\ufe0f\u20e3 Parse Request').first().json.request.payment_tx_hash }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $('1\ufe0f\u20e3 Parse Request').first().json.config.merchant.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "9a0c0569-a791-4d26-bcaf-2712eb0d575c",
      "name": "6\ufe0f\u20e3 Validate Payment",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83e\uddea TEST MODE ACTIVE!\n\nBypasses AgentGatePay verification.\nALWAYS returns validation_passed.\n\n\u26a0\ufe0f REMOVE BEFORE PRODUCTION!",
      "position": [
        1408,
        304
      ],
      "parameters": {
        "jsCode": "const request_data = $('1\ufe0f\u20e3 Parse Request').first().json;\n  const verification = $input.first().json;\n  const config = request_data.config;\n  const resource = request_data.resource;\n\n// Check if verification succeeded\n  if (!verification.verified) {\n    return [{\n      json: {\n        route: \"validation_failed\",\n        http_response: {\n          statusCode: 400,\n          error: \"Payment verification failed\",\n          verified: verification.verified,\n          details: verification.error || \"Payment not found\"\n        }\n      }\n    }];\n  }\n\n  const recipient_ok = verification.to_address.toLowerCase() === config.merchant.wallet_address.toLowerCase();\n  if (!recipient_ok) {\n    return [{\n      json: {\n        route: \"validation_failed\",\n        http_response: {\n          statusCode: 400,\n          error: \"Wrong recipient\",\n          expected: config.merchant.wallet_address,\n          received: verification.to_address\n        }\n      }\n    }];\n  }\n\n  const amount_ok = Math.abs(verification.amount_usd - resource.price_usd) < 0.01;\n  if (!amount_ok) {\n    return [{\n      json: {\n        route: \"validation_failed\",\n        http_response: {\n          statusCode: 400,\n          error: \"Wrong amount\",\n          expected_usd: resource.price_usd,\n          received_usd: verification.amount_usd\n        }\n      }\n    }];\n  }\n\n  return [{\n    json: {\n      ...request_data,\n      verification: verification,\n      route: \"validation_passed\"\n    }\n  }];"
      },
      "typeVersion": 2
    },
    {
      "id": "65e9dc23-b80b-4c7a-b64f-0720fff0273d",
      "name": "6B\ufe0f\u20e3 Route: Valid?",
      "type": "n8n-nodes-base.if",
      "notes": "\u2705 NEW v3.2:\nRoutes valid payments to resource delivery",
      "position": [
        1616,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "validation-passed",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.route }}",
              "rightValue": "validation_passed"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8fca90fb-f0c5-49c5-8b9f-ec4053acb844",
      "name": "7\ufe0f\u20e3 Deliver Resource",
      "type": "n8n-nodes-base.code",
      "notes": "\u2705 v3.2:\nCreates full resource response",
      "position": [
        1808,
        128
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst resource = data.resource;\nconst verification = data.verification;\n\nconst full_data = {\n  success: true,\n  resource_id: resource.id,\n  title: resource.title,\n  price_paid_usd: verification.amountUsd,\n  \n  data: {\n    competitors: [\n      {\n        rank: 1,\n        name: \"Salesforce\",\n        market_share: \"19.8%\",\n        revenue_2024: \"$34.9B\"\n      },\n      {\n        rank: 2,\n        name: \"HubSpot\",\n        market_share: \"8.5%\",\n        revenue_2024: \"$2.2B\"\n      },\n      {\n        rank: 3,\n        name: \"Zendesk\",\n        market_share: \"6.2%\",\n        revenue_2024: \"$1.7B\"\n      },\n      {\n        rank: 4,\n        name: \"Freshworks\",\n        market_share: \"4.1%\",\n        revenue_2024: \"$596M\"\n      },\n      {\n        rank: 5,\n        name: \"Zoho CRM\",\n        market_share: \"3.8%\",\n        revenue_2024: \"$1.1B\"\n      }\n    ],\n    market_analysis: {\n      total_market_size_2024: \"$69.8B\",\n      cagr: \"13.3%\",\n      key_trends: [\n        \"AI-powered insights\",\n        \"Mobile-first experiences\",\n        \"Unified customer data platforms\"\n      ]\n    }\n  },\n  \n  payment: {\n    tx_hash: verification.txHash,\n    verified: true,\n    paid_by: verification.sender,\n    amount_usd: verification.amountUsd\n  },\n  \n  delivered_at: new Date().toISOString()\n};\n\nreturn [{\n  json: {\n    http_response: full_data\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "d2cba580-13ed-4815-afee-e77e296c985d",
      "name": "8\ufe0f\u20e3 Send 200 OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "\u2705 Sends success response with body",
      "position": [
        1984,
        128
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json.http_response) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "bdd63871-3b5c-49e3-b05c-1fda12928fd0",
      "name": "9\ufe0f\u20e3 Send Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "\u2705 Sends error response with body",
      "position": [
        1824,
        464
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json.http_response) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "b2d0e1f0-b135-49d5-9426-136260246560",
      "name": "START HERE",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        16
      ],
      "parameters": {
        "color": 4,
        "width": 500,
        "height": 620,
        "content": "# Seller Resource API\n\n**What it does:** Webhook that sells digital resources to AI agents. Verifies payments via AgentGatePay before delivering content.\n\n**Quick setup (3 min):**\n1. Edit Node 1: Add your wallet address and AgentGatePay API key\n2. Choose payment: coin and network\n3. Activate workflow (toggle top-right)\n4. Copy webhook URL from Node \"\ud83d\udce1 GET /resource/{id}\"\n5. Share URL with buyer agents\n\n**Payment flow:**\n- Request without payment \u2192 Returns 402 with payment details\n- Request with tx_hash \u2192 Verifies via Gateway \u2192 Delivers resource\n\n**Revenue:** You get 99.5% \u00b7 AgentGatePay takes 0.5% commission\n\n**Customize:** Node 1 for price/resources \u00b7 Node 7 for resource data\n\nFor more info:\nhttps://github.com/AgentGatePay/agentgatepay-examples/tree/main/n8n"
      },
      "typeVersion": 1
    },
    {
      "id": "a3d381df-82d8-4298-9f0b-3e63a893cf5a",
      "name": "Sticky Note 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 600,
        "height": 300,
        "content": "## Request Processing\n\nWebhook receives GET request, parses your merchant config and headers, checks if buyer included a payment tx_hash, then routes accordingly."
      },
      "typeVersion": 1
    },
    {
      "id": "0cde0860-3d4f-4f29-bcda-5a7a1ade6827",
      "name": "Sticky Note 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 300,
        "content": "## Payment Verification\n\nAsks AgentGatePay to verify the tx_hash. Checks if payment went to your wallet and matches the resource price. Routes to delivery or error."
      },
      "typeVersion": 1
    },
    {
      "id": "62d614d0-0cf3-44f1-abf5-f0cbc40bb284",
      "name": "Sticky Note 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1168,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 1040,
        "height": 348,
        "content": "## Response Handling\n\nGenerates 402 response when no payment, or delivers the paid resource with 200 OK. Handles errors like wrong amount or invalid tx_hash."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "41504858-cec4-4200-b183-d54c15ee6a30",
  "connections": {
    "2\ufe0f\u20e3 Has Payment?": {
      "main": [
        [
          {
            "node": "5\ufe0f\u20e3 Verify Payment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "3\ufe0f\u20e3 Generate 402",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3\ufe0f\u20e3 Generate 402": {
      "main": [
        [
          {
            "node": "4\ufe0f\u20e3 Send 402",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1\ufe0f\u20e3 Parse Request": {
      "main": [
        [
          {
            "node": "2\ufe0f\u20e3 Has Payment?",
            "type": "main",
            "index": 0
          },
          {
            "node": "9\ufe0f\u20e3 Send Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5\ufe0f\u20e3 Verify Payment": {
      "main": [
        [
          {
            "node": "6\ufe0f\u20e3 Validate Payment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6B\ufe0f\u20e3 Route: Valid?": {
      "main": [
        [
          {
            "node": "7\ufe0f\u20e3 Deliver Resource",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "9\ufe0f\u20e3 Send Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce1 GET /resource/{id}": {
      "main": [
        [
          {
            "node": "1\ufe0f\u20e3 Parse Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6\ufe0f\u20e3 Validate Payment": {
      "main": [
        [
          {
            "node": "6B\ufe0f\u20e3 Route: Valid?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7\ufe0f\u20e3 Deliver Resource": {
      "main": [
        [
          {
            "node": "8\ufe0f\u20e3 Send 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}