{
  "id": "iOBvq8tJmbslKLvM",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "n8n Facilitator with 1Shot API",
  "tags": [
    {
      "id": "ChlnN7rtKHJMnWmM",
      "name": "x402",
      "createdAt": "2025-06-19T04:23:28.149Z",
      "updatedAt": "2025-06-19T04:23:28.149Z"
    }
  ],
  "nodes": [
    {
      "id": "18ef87da-599a-4aa9-89cb-dab6ac024abe",
      "name": "Simulate Payment",
      "type": "n8n-nodes-1shot.oneShot",
      "position": [
        208,
        32
      ],
      "parameters": {
        "params": "={\n  \"from\": \"{{ $json.body.paymentPayload.authorization.from }}\",\n  \"to\": \"{{ $json.body.paymentPayload.authorization.to }}\",\n  \"value\": \"{{ $json.body.paymentPayload.authorization.value }}\",\n  \"validAfter\": \"{{ $json.body.paymentPayload.authorization.validAfter }}\",\n  \"validBefore\": \"{{ $json.body.paymentPayload.authorization.validBefore }}\",\n  \"nonce\": \"{{ $json.body.paymentPayload.authorization.nonce }}\",\n  \"v\": \"{{ $json.body.paymentRequirements.v }}\",\n  \"r\": \"{{ $json.body.paymentRequirements.r }}\",\n  \"s\": \"{{ $json.body.paymentRequirements.s }}\"\n} ",
        "operation": "simulate",
        "contractMethodId": "={{ $json.paymentConfig.contractMethodId }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d6d7add8-77b1-4083-9dbb-f4140e96dd56",
      "name": "/verify",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -688,
        416
      ],
      "parameters": {
        "path": "/verify",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "734689a3-1a5a-4e75-aeff-0cfe1906147a",
      "name": "/settle",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -688,
        608
      ],
      "parameters": {
        "path": "/settle",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "21939197-b339-42fc-94d8-2bbdb2442a0e",
      "name": "Settlement Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        432,
        224
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "={\n  \"success\": {{ $json.status === \"Completed\" }},\n  \"error\": {{ JSON.stringify($json.failureReason) }},\n  \"txHash\": \"{{ $json.transactionHash }}\",\n  \"networkId\": \"{{ $json.chainId }}\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "5fa377a6-f450-497d-bec0-ad19c08bdcfc",
      "name": "Verify Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        432,
        32
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "={\n  \"isValid\": {{ $json.success }},\n  \"invalidReason\": \"{{ $json.error.reason }}\"\n} "
      },
      "typeVersion": 1.3
    },
    {
      "id": "3a22826f-7857-4e5b-9239-a504b6a4b918",
      "name": "Response: Bad POST Body (/verify)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -16,
        704
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "{\n  \"isValid\": false,\n  \"invalidReason\": \"Incorrect or missing payload arguments\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "954e3c34-dad9-4c62-b5a6-97cff5a642dd",
      "name": "Response: Bad POST Body (/settle)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -16,
        896
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "={\n  \"success\": false,\n  \"error\": \"Missing or incorrect POST body\",\n  \"txHash\": null,\n  \"networkId\":  {{ JSON.stringify($json.body.paymentRequirements.network) }}\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "63d9fe6a-7618-429b-9e47-db9451542337",
      "name": "1Shot API Submit & Wait",
      "type": "n8n-nodes-1shot.oneShotSynch",
      "position": [
        208,
        224
      ],
      "parameters": {
        "params": "={\n  \"from\": \"{{ $json.body.paymentPayload.authorization.from }}\",\n  \"to\": \"{{ $json.body.paymentPayload.authorization.to }}\",\n  \"value\": \"{{ $json.body.paymentPayload.authorization.value }}\",\n  \"validAfter\": \"{{ $json.body.paymentPayload.authorization.validAfter }}\",\n  \"validBefore\": \"{{ $json.body.paymentPayload.authorization.validBefore }}\",\n  \"nonce\": \"{{ $json.body.paymentPayload.authorization.nonce }}\",\n  \"v\": \"{{ $json.body.paymentRequirements.v }}\",\n  \"r\": \"{{ $json.body.paymentRequirements.r }}\",\n  \"s\": \"{{ $json.body.paymentRequirements.s }}\"\n} ",
        "additionalFields": {
          "memo": "="
        },
        "contractMethodId": "={{ $json.paymentConfig.contractMethodId }}"
      },
      "credentials": {
        "oneShotOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "019b8699-64d1-4404-9ba2-3c61a377fd8a",
      "name": "Check POST Payload",
      "type": "n8n-nodes-base.if",
      "position": [
        -464,
        512
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "2ff83590-61f3-41d8-8500-a96103c3844c",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.x402Version }}",
              "rightValue": ""
            },
            {
              "id": "8aa3ceb5-3fb4-4561-a4f5-3c030e190f9f",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.signature }}",
              "rightValue": ""
            },
            {
              "id": "d43e938b-1c66-49dc-9e45-74d7cd152790",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.from }}",
              "rightValue": ""
            },
            {
              "id": "b962c55e-5e76-4bb9-a6cb-77a972c65b68",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.to.toLowerCase() }}",
              "rightValue": "={{ $json.body.paymentRequirements.payTo.toLowerCase() }}"
            },
            {
              "id": "0d49d306-c7e1-4625-b462-cb710ded7ca0",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.value }}",
              "rightValue": ""
            },
            {
              "id": "92aa41a4-4530-4b62-a5ed-27e9bd9c0fee",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.validAfter }}",
              "rightValue": ""
            },
            {
              "id": "ad7542b4-a9e2-4e34-91b4-27cbedf70abb",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.validBefore }}",
              "rightValue": ""
            },
            {
              "id": "e8b8fc7a-7307-4e6b-a038-d9f63cffed94",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentPayload.authorization.nonce }}",
              "rightValue": ""
            },
            {
              "id": "723bbc2a-285e-4021-8a7c-d785c429754d",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentRequirements.asset }}",
              "rightValue": ""
            },
            {
              "id": "f3042c49-591a-4085-a22e-33f35005b2bc",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.body.paymentRequirements.network }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "08df85be-f602-4710-a9ca-340e39c9816b",
      "name": "/supported",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -688,
        1120
      ],
      "parameters": {
        "path": "supported",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "5b19047c-d340-4cfc-9909-b7589b999a32",
      "name": "Response: Return Supported Networks",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -240,
        1120
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "={\n  \"kinds\": {{ JSON.stringify($json.kinds) }}\n} "
      },
      "typeVersion": 1.3
    },
    {
      "id": "ac002b7a-108e-49b6-bed7-16bb8477fe6e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        64
      ],
      "parameters": {
        "width": 448,
        "height": 464,
        "content": "## /verify endpoint\n\nThe verify endpoint will check that the given `x-payment` header, given the associated `paymentRequirements`, are valid. If the payment details are valid this endpoint will return:\n```sh\n{\n  isValid: true;\n  invalidReason: \"\";\n}\n```\n\nIf the endpoint determines that the payment details will revert for any reason, it will return with: \n```sh\n{\n  isValid: false;\n  invalidReason: \"<Smart Contract Revert Error>\";\n}\n```\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cea02913-92b7-45aa-bcb2-1e3dc3a8d588",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        592
      ],
      "parameters": {
        "width": 432,
        "height": 464,
        "content": "## /settle endpoint\n\nThe settle endpoint will attempt to settle a payment to the target blockchain given the provided payment details. If this endpoint fails it will return with:\n```sh\n{\n  success: false;\n  error: \"<Reason for tx failure>\";\n  txHash: null;\n  networkId: \"<network name>\";\n}\n```\n\nIf the endpoint succeeds, it will return:\n```sh\n{\n  success: true;\n  error: null;\n  txHash: \"transaction hash\";\n  networkId: \"<network name>\";\n}\n```\n"
      },
      "typeVersion": 1
    },
    {
      "id": "9cd414aa-fa67-4c9c-8177-6a3568d43af2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        48
      ],
      "parameters": {
        "width": 320,
        "height": 240,
        "content": "## Accepted Tokens Config \n\nYou must edit the payment tokens `config` object in the `Lookup Payments Config` node with the token details of all tokens you wish to support with your facilitator. \n\n*Important*: Be sure to import the contract methods for the appropriate tokens into your 1Shot API node. "
      },
      "typeVersion": 1
    },
    {
      "id": "e788d782-8540-437e-b86f-a3d14c75b885",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        1152
      ],
      "parameters": {
        "width": 416,
        "height": 320,
        "content": "## /supported endpoint\n\nThis endpoint returns the blockchain networks your facilitator will support. Its output looks like: \n\n\n```sh\n{\n  kinds: [\n    {\n      \"scheme\": string,\n      \"network\": string,\n    }\n  ]\n}\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "64f5beea-0952-4aca-9c07-3ec3eef523d8",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        1344
      ],
      "parameters": {
        "width": 384,
        "height": 176,
        "content": "## Supported Networks Config\n\nBe sure to update the `Supported Networks Config` node to reflect the networks you have configured your 1Shot API account to process. "
      },
      "typeVersion": 1
    },
    {
      "id": "c6292c7a-cac1-46be-a61c-b80170aa1a93",
      "name": "Supported Networks Config",
      "type": "n8n-nodes-base.code",
      "onError": "continueErrorOutput",
      "position": [
        -464,
        1120
      ],
      "parameters": {
        "jsCode": "const input = $input.all()\n\n\nconst kinds = [\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"base-mainnet\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"base-sepolia\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"sepolia\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"avalanche\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"avalanche-fuji\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"arbitrum-mainnet\",\n    },\n    {\n      \"scheme\": \"exact\",\n      \"network\": \"ethereum-mainnet\",\n    }\n  ]\n\n$input.first().json.kinds = kinds;\n\nreturn $input.all();\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9fb18099-c840-47af-b8d6-9f8107c05dd3",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2000,
        400
      ],
      "parameters": {
        "width": 800,
        "height": 928,
        "content": "## Example Facilitator Curl Request\n\nHere is a complete curl request you can use to test your node (be sure to change the URL to point at your n8n webhook):\n\n```sh\ncurl -X POST \\\n  https://n8n.1shotapi.dev/webhook-test/settle \\\n  -H \"User-Agent: CustomUserAgent/1.0\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n        \"x402Version\": 1,\n        \"paymentPayload\": {\n            \"authorization\":{\n                \"from\":\"0x9fEad8B19C044C2f404dac38B925Ea16ADaa2954\",\n                \"to\":\"0x9fead8b19c044c2f404dac38b925ea16adaa2954\",\n                \"value\":\"1000000\",\n                \"validAfter\":\"1755714180\",\n                \"validBefore\":\"1755714520\",\n                \"nonce\":\"0x19f7c8ccf93c450727021041feb01ed0fda4b18cc90f41c9c0f0ff18a2310441\"\n            },\n            \"signature\":\"0x5fe02d768cc1b342c48c6312d0479308bb256ea2af4c59ce34aec3a5ccb1539b542b786e519ab44de5405c2dfc8a0f860fa1aa9ff4436991ad6260d4ae2927941c\"\n        },\n        \"paymentRequirements\": {\n            \"scheme\": \"exact\",\n            \"network\": \"sepolia\",\n            \"maxAmountRequired\": \"5000000\",\n            \"resource\": \"https://n8n.1shotapi.dev/webhook/gas-station\",\n            \"description\": \"Swap stablecoins for gas tokens\",\n            \"mimeType\": \"\",\n            \"outputSchema\": {},\n            \"payTo\": \"0x9fEad8B19C044C2f404dac38B925Ea16ADaa2954\",\n            \"maxTimeoutSeconds\": 150,\n            \"asset\": \"0xcac524bca292aaade2df8a05cc58f0a65b1b3bb9\",\n            \"extra\": {\n                \"name\": \"PayPal USD\",\n                \"version\": \"1\"\n            }\n        }\n  }'\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "7c69392c-d424-4639-909e-588a5f17cee2",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        -240
      ],
      "parameters": {
        "width": 432,
        "height": 224,
        "content": "## Create Your 1Shot API Credential\n\nDon't forget to authenticate against your 1Shot API business by creating an n8n credential. \n\nClick on one of the 1Shot API nodes, then click on `Credential to connect with`, then enter you API key, secret, and business id. "
      },
      "typeVersion": 1
    },
    {
      "id": "efa373f0-b6ae-4a46-b6f2-ec6f6d2eae67",
      "name": "Unsupported Token",
      "type": "n8n-nodes-base.if",
      "position": [
        -16,
        512
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "185b904e-d8c8-4605-9075-531abc762b46",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.webhookUrl }}",
              "rightValue": "verify"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c7ab50fa-af33-41ec-849f-a53f7ec7b54d",
      "name": "verify or settle",
      "type": "n8n-nodes-base.if",
      "position": [
        -16,
        128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "185b904e-d8c8-4605-9075-531abc762b46",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.webhookUrl }}",
              "rightValue": "verify"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b80d7ac0-14bc-4dfb-936b-a09c3644ba53",
      "name": "Response: Unsupported Token (/verify)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        208,
        416
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "{\n  \"isValid\": false,\n  \"invalidReason\": \"Unsupported payment token\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "f57b3f31-2f63-482a-87d7-cdeb8884f0de",
      "name": "Response: Unsupported Token (/settle)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        208,
        608
      ],
      "parameters": {
        "options": {
          "responseCode": 402
        },
        "respondWith": "json",
        "responseBody": "={\n  \"success\": false,\n  \"error\": \"Unsupported payment token\",\n  \"txHash\": null,\n  \"networkId\": {{ JSON.stringify(($json.error.match(/<([^>]+)>/) || [])[1] || null) }}\n} "
      },
      "typeVersion": 1.3
    },
    {
      "id": "c94b228a-7a92-45b9-9ded-fb34186eaa2e",
      "name": "Bad Payload",
      "type": "n8n-nodes-base.if",
      "position": [
        -240,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "185b904e-d8c8-4605-9075-531abc762b46",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.webhookUrl }}",
              "rightValue": "verify"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "68d961ac-3d63-40ff-aecb-acb5d3c8e8f4",
      "name": "Lookup Payment Configs & Split Signature",
      "type": "n8n-nodes-base.code",
      "onError": "continueErrorOutput",
      "position": [
        -240,
        320
      ],
      "parameters": {
        "jsCode": "const fromToken = $input.first().json.body.paymentRequirements.asset;\nconst fromChain = $input.first().json.body.paymentRequirements.network;\n\n// Here is where you configure the payments tokens you will facilitate\n// the contractMethodId comes from your 1Shot API account. Import a `transferWithAuthorization`\n// method from an x402-compatible payment token and put its contractMethodId here. \n// IMPORTANT: Be sure that you are using a `transferWithAuthorization` function that takes\n// r, s, and v signature components. \nconst config = {\n  \"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\": {\n    tokenAddress: \"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\",\n    chain: \"8453\",\n    name: \"USD Coin\",\n    version: \"2\",\n    contractMethodId: \"\",\n    network: \"base-mainnet\"\n  },\n  \"0x036cbd53842c5426634e7929541ec2318f3dcf7e\": {\n    tokenAddress: \"0x036cbd53842c5426634e7929541ec2318f3dcf7e\",\n    chain: \"84532\",\n    name: \"USDC\",\n    version: \"2\",\n    contractMethodId: \"\",\n    network: \"base-sepolia\"\n  },\n  \"0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e\": {\n    tokenAddress: \"0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e\",\n    chain: \"43114\",\n    name: \"USD Coin\",\n    version: \"2\",\n    contractMethodId: \"\",\n    network: \"avalanche\"\n  },\n  \"0xaf88d065e77c8cc2239327c5edb3a432268e5831\": {\n    tokenAddress: \"0xaf88d065e77c8cc2239327c5edb3a432268e5831\",\n    chain: \"42161\",\n    name: \"USD Coin\",\n    version: \"2\",\n    contractMethodId: \"\",\n    network: \"arbitrum-mainnet\"\n  },\n  \"0xcACYOUR_TWILIO_ACCOUNT_SIDb3bb9\": {\n    tokenAddress: \"0xcACYOUR_TWILIO_ACCOUNT_SIDb3bb9\",\n    chain: \"11155111\",\n    name: \"PayPal USD\",\n    version: \"1\",\n    contractMethodId: \"\",\n    network: \"sepolia\"\n  },\n  \"0x6c3ea9036406852006290770BEdFcAbA0e23A0e8\": {\n    tokenAddress: \"0x6c3ea9036406852006290770BEdFcAbA0e23A0e8\",\n    chain: \"1\",\n    name: \"PayPal USD\",\n    version: \"1\",\n    contractMethodId: \"\",\n    network: \"ethereum-mainnet\"\n  }\n};\n\nfunction splitSignature(sigHex) {\n  // Remove \"0x\" prefix if present\n  const hex = sigHex.startsWith(\"0x\") ? sigHex.slice(2) : sigHex;\n\n  // Convert hex to byte array\n  const bytes = new Uint8Array(hex.length / 2);\n  for (let i = 0; i < bytes.length; i++) {\n    bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\n  }\n\n  if (bytes.length !== 65) {\n    throw new Error(`Invalid signature length: got ${bytes.length} bytes`);\n  }\n\n  // Convert byte ranges to hex strings\n  const toHex = (arr) =>\n    \"0x\" + Array.from(arr).map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n  const r = toHex(bytes.slice(0, 32));\n  const s = toHex(bytes.slice(32, 64));\n\n  // Normalize v\n  let v = bytes[64];\n  if (v === 0) v = 27;\n  else if (v === 1) v = 28;\n  else if (v !== 27 && v !== 28 && v >= 35) {\n    v = (v & 1) ? 27 : 28; // EIP-155\n  }\n\n  const vHex = \"0x\" + v.toString(16).padStart(2, \"0\");\n\n  return { r, s, v: vHex };\n}\n\nconst splitSig = splitSignature($input.first().json.body.paymentPayload.signature);\n$input.first().json.body.paymentRequirements.r = splitSig.r;\n$input.first().json.body.paymentRequirements.s = splitSig.s;\n$input.first().json.body.paymentRequirements.v = splitSig.v;\n\n// Check if fromToken exists in config\nif (!config[fromToken.toLowerCase()]) {\n  throw new Error(`Token ${fromToken} not found in configuration`);\n}\n\n// Optionally you could also validate the chain if needed\nif (config[fromToken.toLowerCase()].network !== fromChain) {\n  throw new Error(`Invalid chain for token ${fromToken} on <${fromChain}>`);\n}\n\n// Add the parsed JSON object to the input\n$input.first().json.paymentConfig = config[fromToken.toLowerCase()];\n\nreturn $input.all();\n\n"
      },
      "typeVersion": 2
    },
    {
      "id": "788f68b0-4429-4828-b77a-4e58b4dad955",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1904,
        -80
      ],
      "parameters": {
        "width": 576,
        "height": 432,
        "content": "## Docs & Setup Tutorial\n\n@[youtube](J4ftyV-wz50)\n\nYou can check out our [docs link](https://docs.1shotapi.com/automation/n8n.html#host-your-own-x402-facilitator) or start with the [YouTube tutorial](https://youtu.be/J4ftyV-wz50) for orientation. "
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "855725ba-996a-4cbf-9367-753b51aa979b",
  "connections": {
    "/settle": {
      "main": [
        [
          {
            "node": "Check POST Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "/verify": {
      "main": [
        [
          {
            "node": "Check POST Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "/supported": {
      "main": [
        [
          {
            "node": "Supported Networks Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bad Payload": {
      "main": [
        [
          {
            "node": "Response: Bad POST Body (/verify)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Response: Bad POST Body (/settle)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simulate Payment": {
      "main": [
        [
          {
            "node": "Verify Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "verify or settle": {
      "main": [
        [
          {
            "node": "Simulate Payment",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "1Shot API Submit & Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Unsupported Token": {
      "main": [
        [
          {
            "node": "Response: Unsupported Token (/verify)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Response: Unsupported Token (/settle)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check POST Payload": {
      "main": [
        [
          {
            "node": "Lookup Payment Configs & Split Signature",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Bad Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1Shot API Submit & Wait": {
      "main": [
        [
          {
            "node": "Settlement Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Settlement Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supported Networks Config": {
      "main": [
        [
          {
            "node": "Response: Return Supported Networks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Payment Configs & Split Signature": {
      "main": [
        [
          {
            "node": "verify or settle",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Unsupported Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}