8
n8n 한국어amn8n.com

n8n API와 Bootstrap를 사용하여 Webhooks를 생성하는 자문화 API 포털

고급

이것은Document Extraction, Multimodal AI분야의자동화 워크플로우로, 17개의 노드를 포함합니다.주로 N8n, Set, Code, Html, Webhook 등의 노드를 사용하며. 사용n8n API와Bootstrap로 Webhooks를 통해 자동 문서화된 API 포털 생성

사전 요구사항
  • HTTP Webhook 엔드포인트(n8n이 자동으로 생성)
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
  "meta": {
    "instanceId": "e860732ed76ff1de8212e780b2d62bd140dee0b71e6ccf7172d54e965acae43d",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "a59b516a-e188-4364-8722-f83fd00ed0f0",
      "name": "집계",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        120,
        -300
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "3ab41431-6298-4380-aaec-d0e29f7f9cb5",
      "name": "Webhook 트리거",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -700,
        460
      ],
      "webhookId": "e98f9bf5-f5ad-46fb-a93c-08218eea8d5e",
      "parameters": {
        "path": "api-doc",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "286e23f0-44c8-46c4-bfd2-8aab6eae245b",
      "name": "Configs",
      "type": "n8n-nodes-base.set",
      "position": [
        -480,
        460
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "9a243289-a359-47fd-9155-a809a910b8f7",
              "name": "name_doc",
              "type": "string",
              "value": "N8N Example Doc"
            },
            {
              "id": "59992f15-d27d-454c-9c1f-a66f0674c7bb",
              "name": "version",
              "type": "string",
              "value": "v.0.1"
            },
            {
              "id": "f0633ecb-b0c8-4e55-8285-51aa05492420",
              "name": "description",
              "type": "string",
              "value": "Example description"
            },
            {
              "id": "2da37a16-f97a-4ec8-9d9c-13f09bea1d39",
              "name": "url_base",
              "type": "string",
              "value": "n8n.io/"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b910c088-c3c6-4bfc-9856-5294891e4cd0",
      "name": "메모",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -370,
        -400
      ],
      "parameters": {
        "color": 2,
        "width": 860,
        "height": 260,
        "content": "## Get Workflow and filter\n"
      },
      "typeVersion": 1
    },
    {
      "id": "add44468-ffba-401e-a119-3e25c4870ece",
      "name": "메모1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -360,
        -120
      ],
      "parameters": {
        "color": 6,
        "width": 760,
        "height": 400,
        "content": "## webhook for testing"
      },
      "typeVersion": 1
    },
    {
      "id": "1de3f20f-152c-4f81-b42d-cc9e03f5bf0d",
      "name": "Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        120,
        -40
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.1
    },
    {
      "id": "0a7a9d55-5b34-4129-952d-c982ebcc3d7c",
      "name": "RespondHTML",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        180,
        460
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "={{$json.html}}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "f85d91a0-16ec-4f79-870a-dfc24f954469",
      "name": "MakeFullHTML",
      "type": "n8n-nodes-base.html",
      "position": [
        -40,
        460
      ],
      "parameters": {
        "html": "<html>\n<head>\n  <title>{{$('Configs').item.json.name_doc}}</title>\n  <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css\">\n  <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n  <style>\n    :root {\n      --bs-body-bg: #1a1a1a;\n      --bs-body-color: #e0e0e0;\n      --bs-border-color: #444;\n      --bs-accordion-bg: #2b2b2b;\n      --bs-accordion-color: #e0e0e0;\n      --bs-accordion-button-color: #e0e0e0;\n      --bs-accordion-border-color: #444;\n      --bs-accordion-button-active-bg: #3c3c3c;\n      --bs-accordion-button-active-color: #ffffff;\n      --bs-accordion-button-focus-border-color: #007bff;\n      --bs-accordion-button-focus-box-shadow: 0 0 0 0.25rem rgba(0, 123, 255, 0.25);\n    }\n    .method {\n      display: inline-block;\n      padding: 0.3em 0.8em;\n      border-radius: 0.25rem;\n      font-weight: bold;\n      font-size: 0.9em;\n      color: white;\n      text-transform: uppercase;\n      margin-right: 1rem;\n    }\n    .method-post { background-color: #49cc90; }\n    .method-get { background-color: #61affe; }\n    .endpoint-path {\n      font-family: monospace;\n      font-size: 1.1em;\n      color: #ccc;\n    }\n    pre {\n      background-color: #161B22;\n      padding: 1rem;\n      border-radius: 0.25rem;\n      white-space: pre-wrap;\n      word-break: break-all;\n      border: 1px solid var(--bs-border-color);\n    }\n    code { color: #c9d1d9; }\n    .accordion-button:not(.collapsed) {\n        box-shadow: inset 0 -1px 0 var(--bs-accordion-border-color);\n    }\n  </style>\n</head>\n<body class=\"p-4\">\n  <div class=\"container\">\n    <div class=\"d-flex align-items-baseline mb-4\">\n      <h1 class=\"text-white me-3\">{{$('Configs').item.json.name_doc}}</h1>\n      <p class=\"text-white-50 me-3\">{{$('Configs').item.json.description}}</p>\n      <span class=\"badge bg-secondary\">{{$('Configs').item.json.version}}</span>\n    </div>\n    \n    {{ $json.htmlContent || `\n<div class=\"alert alert-danger d-flex align-items-center mt-4\" role=\"alert\">\n  <i class=\"bi bi-x-octagon-fill me-3\" style=\"font-size: 2rem;\"></i>\n  <div>\n    <h4 class=\"alert-heading\">Documentation Generation Failed!</h4>\n    <p>An error occurred while trying to generate the API documentation from the sub-workflow.</p>\n    <hr>\n    <p class=\"mb-1\"><strong>Please check the following:</strong></p>\n    <ul>\n      <li>Ensure the sub-workflow (the one that generates the accordion) executed successfully and produced an output named <code>htmlContent</code>.</li>\n      <li>Verify that at least one of your workflows is active and contains a correctly configured <code>API_DOCS</code> node.</li>\n      <li>Check the n8n execution logs for more detailed error messages from the sub-workflow.</li>\n    </ul>\n  </div>\n</div>\n`}}\n\n\n    </div>\n <footer class=\"mt-5 pt-4 text-center text-white-50\">\n  <p>\n    Created by <a href=\"https://www.linkedin.com/in/matheus-pedrosa-custodio/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"link-light text-decoration-none\">\n      <i class=\"bi bi-linkedin\"></i> Matheus Pedrosa\n    </a>\n  </p>\n</footer>\n  \n  <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js\"></script>\n</body>\n</html>"
      },
      "typeVersion": 1.2
    },
    {
      "id": "0bd66854-cf1b-46b5-ad75-e0d7ef9b71d4",
      "name": "ExecuteSubWorkflow",
      "type": "n8n-nodes-base.executeWorkflow",
      "onError": "continueRegularOutput",
      "position": [
        -260,
        460
      ],
      "parameters": {
        "options": {
          "waitForSubWorkflow": true
        },
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "y2xOdk7RyRoS2sgF",
          "cachedResultName": "Documentation"
        },
        "workflowInputs": {
          "value": {},
          "schema": [
            {
              "id": "url_base",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "url_base",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "43a02f1b-9f18-4148-9705-2c3347997cfa",
      "name": "Execute",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -320,
        -300
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "url_base"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "91ad9f92-adf3-4a8c-af48-3d1e5cd06678",
      "name": "GetWorkflows",
      "type": "n8n-nodes-base.n8n",
      "position": [
        -100,
        -300
      ],
      "parameters": {
        "filters": {
          "tags": "",
          "activeWorkflows": true
        },
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "id": "fTE1pX6nL40KSIdW",
          "name": "n8n account"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "alwaysOutputData": false
    },
    {
      "id": "c28819b2-2e5d-4732-9a68-0d5045dcb59e",
      "name": "필터Workflows",
      "type": "n8n-nodes-base.code",
      "position": [
        340,
        -300
      ],
      "parameters": {
        "jsCode": "const allWorkflows = $('Aggregate').last().json.data;\nlet html = '';\n\nconst documentedWebhookWorkflows = allWorkflows.filter(item => {\n  if (!item.nodes || item.nodes.length === 0) {\n    return false;\n  }\n  const hasWebhook = item.nodes.some(node => node.type === 'n8n-nodes-base.webhook');\n  const hasDocsNote = item.nodes.some(node => node.type === 'n8n-nodes-base.set' && node.name === 'API_DOCS');\n  return hasWebhook && hasDocsNote;\n});\n\n\nif (documentedWebhookWorkflows.length > 0) {\n  html += '<div class=\"accordion\" id=\"docsAccordion\">';\n\n  const n8nBaseUrl = $(\"Execute\").last().json.url_base || 'https://n8n.io/';\n\n  for (const workflow of documentedWebhookWorkflows) {\n    const docsNode = workflow.nodes.find(n => n.name === 'API_DOCS');\n\n    if (docsNode) {\n      const jsonString = docsNode.parameters.jsonOutput || JSON.stringify(docsNode.parameters.docsData);\n      let docsData = {};\n      let webhookNode = null;\n\n      try {\n        docsData = JSON.parse(jsonString);\n        webhookNode = workflow.nodes.find(n => { return n.type === 'n8n-nodes-base.webhook' && n.name === docsData.webhook });\n      } catch (e) {\n        console.error(`Erro ao parsear JSON no workflow: ${workflow.name}`, e);\n        continue;\n      }\n\n      if(webhookNode){\n        const method = (docsData.method || \"POST\").toUpperCase();\n        const uniqueId = webhookNode.parameters.path.replace(/[^a-zA-Z0-9]/g, '');\n\n        // --- make CURL\n        const fullUrl = `${n8nBaseUrl}webhook/${webhookNode.parameters.path}`;\n\n        let curlCommand = `curl -X ${method}\\\\`;\n        if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n          const requestBodyString = JSON.stringify(docsData.requestBody || {});\n          curlCommand += `\n          -H 'Content-Type: application/json' \\\\\n          -d '${requestBodyString}' \\\\`;\n                }\n                curlCommand += `\n          ${fullUrl}`;\n\n        html += `\n          <div class=\"accordion-item\">\n            <h2 class=\"accordion-header\" id=\"heading-${uniqueId}\">\n              <button class=\"accordion-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#collapse-${uniqueId}\" aria-expanded=\"false\" aria-controls=\"collapse-${uniqueId}\">\n                <span class=\"method method-${method.toLowerCase()}\">${method}</span>\n                <span class=\"endpoint-path\">/webhook/${webhookNode.parameters.path}</span>\n              </button>\n            </h2>\n            <div id=\"collapse-${uniqueId}\" class=\"accordion-collapse collapse\" aria-labelledby=\"heading-${uniqueId}\" data-bs-parent=\"#docsAccordion\">\n              <div class=\"accordion-body\">\n                <p><strong>${docsData.summary || 'No summary'}</strong></p>\n                <p>${docsData.description || 'No description.'}</p>\n                <hr style=\"border-color: var(--bs-border-color);\">\n                \n                <h6>cURL Command:</h6>\n                <pre><code>${curlCommand}</code></pre>\n                \n                <h6>Request Body:</h6>\n                <pre><code>${JSON.stringify(docsData.requestBody || {}, null, 2)}</code></pre>\n                <h6>Success Response (${docsData.successCode || 'N/A'}):</h6>\n                <pre><code>${JSON.stringify(docsData.successResponse || {}, null, 2)}</code></pre>\n                <h6>Error Response (${docsData.errorCode || 'N/A'}):</h6>\n                <pre><code>${JSON.stringify(docsData.errorResponse || {}, null, 2)}</code></pre>\n              </div>\n            </div>\n          </div>\n        `;\n      }\n    }\n  }\n  html += '</div>';\n} else {\n  html += '<div class=\"alert alert-info\">Nenhum endpoint documentado foi encontrado.</div>';\n}\n\nreturn [{\n  json: {\n    htmlContent: html\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "78526a12-613c-4530-9a6f-bb612036addf",
      "name": "메모2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -940,
        -400
      ],
      "parameters": {
        "color": 4,
        "width": 540,
        "height": 700,
        "content": "### Live n8n API Documentation Generator\n\n**Author:** Matheus Pedrosa | https://www.linkedin.com/in/matheus-pedrosa-custodio/\n**Version:** 1.0\n**Date:** 2025-08-21\n\n## Summary\nThis is a \"meta-workflow\" that acts as an engine to automatically generate a live, interactive HTML documentation page for your n8n instance's webhooks. It scans all active workflows, finds the ones designated for documentation, and renders a single, professional, dark-themed page.\n\n## Key Feature\nThe core logic relies on a **convention-based discovery**. To include a webhook in the documentation, you simply add a `Set` node named **`API_DOCS`** to that workflow and fill in a JSON object with the endpoint's metadata (summary, request body, responses, etc.). This generator then automatically parses that data to build the documentation page.\n\n## Setup (Quick Checklist)\n1.  **`API_DOCS` Nodes:** In every workflow you want to document, add a `Set` node named `API_DOCS` and provide the necessary JSON metadata (especially the `webhookPath`).\n2.  **`GetWorkflows` Node:** Configure this node with your `n8n API` credentials. It needs permission to read all workflows.\n3.  **`Configs` Node:** Customize the global settings for your documentation page, such as the main title (`name_doc`), description, and version.\n4.  **`Webhook` Trigger:** The URL of this workflow's trigger is the public URL for your final documentation page."
      },
      "typeVersion": 1
    },
    {
      "id": "602d0cd7-558e-4360-b385-bf9824f9278b",
      "name": "Webhook 트리거1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -320,
        -40
      ],
      "webhookId": "15105da5-96ca-472f-a7db-2ddc2e8b0891",
      "parameters": {
        "path": "15105da5-96ca-472f-a7db-2ddc2e8b0891",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "6283f30d-d1eb-4a7b-9f97-73834d7c060f",
      "name": "API_DOCS",
      "type": "n8n-nodes-base.set",
      "position": [
        -320,
        120
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"expose\": true,\n  \"webhook\": \"Webhook1\",\n  \"summary\": \"Title test\",\n  \"method\":\"get\",\n  \"description\": \"Hey community, look at this cool workflow I'm doing.\",\n  \"tags\": [\n    \"test\",\n    \"tag_0101\"\n  ],\n  \"requestBody\": {},\n  \"successCode\": 200,\n  \"successResponse\": {\n    \"status\": 200,\n    \"message\": \"Workflow start\"\n  },\n  \"errorCode\": 400,\n  \"errorResponse\": {\n    \"status\": 500,\n    \"message\": \"Workflow error\"\n  }\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "57843c34-afb5-401e-86dc-8aa22c242263",
      "name": "FakeResponse",
      "type": "n8n-nodes-base.code",
      "position": [
        -100,
        -40
      ],
      "parameters": {
        "jsCode": "return {\n    \"status\": 200,\n    \"message\": \"Workflow start\"\n  }"
      },
      "typeVersion": 2
    },
    {
      "id": "29b6b6ea-917b-47a3-b8a1-ff017b0a10a5",
      "name": "메모3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -940,
        400
      ],
      "parameters": {
        "width": 150,
        "height": 200,
        "content": "### Create documentation page\n\n![](https://cdn-icons-png.flaticon.com/512/4028/4028647.png)"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "286e23f0-44c8-46c4-bfd2-8aab6eae245b": {
      "main": [
        [
          {
            "node": "0bd66854-cf1b-46b5-ad75-e0d7ef9b71d4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "43a02f1b-9f18-4148-9705-2c3347997cfa": {
      "main": [
        [
          {
            "node": "91ad9f92-adf3-4a8c-af48-3d1e5cd06678",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "286e23f0-44c8-46c4-bfd2-8aab6eae245b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook1": {
      "main": [
        [
          {
            "node": "57843c34-afb5-401e-86dc-8aa22c242263",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "FilterWorkflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "57843c34-afb5-401e-86dc-8aa22c242263": {
      "main": [
        [
          {
            "node": "1de3f20f-152c-4f81-b42d-cc9e03f5bf0d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "91ad9f92-adf3-4a8c-af48-3d1e5cd06678": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f85d91a0-16ec-4f79-870a-dfc24f954469": {
      "main": [
        [
          {
            "node": "0a7a9d55-5b34-4129-952d-c982ebcc3d7c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "FilterWorkflows": {
      "main": [
        []
      ]
    },
    "0bd66854-cf1b-46b5-ad75-e0d7ef9b71d4": {
      "main": [
        [
          {
            "node": "f85d91a0-16ec-4f79-870a-dfc24f954469",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
자주 묻는 질문

이 워크플로우를 어떻게 사용하나요?

위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.

이 워크플로우는 어떤 시나리오에 적합한가요?

고급 - 문서 추출, 멀티모달 AI

유료인가요?

이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수17
카테고리2
노드 유형10
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

저자
Matheus Pedrosa

Matheus Pedrosa

@julinho

I am a software engineer specializing in automations, with extensive experience on the N8N platform. With solid skills in JavaScript, Go, .NET, and C#, I am equipped to develop efficient and scalable solutions.

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34