{
  "name": "FetchFox YouTube transcript starter v1",
  "nodes": [
    {
      "id": "manual-run",
      "name": "Manual run",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        240
      ],
      "parameters": {}
    },
    {
      "id": "configure-input",
      "name": "Configure input",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        240,
        240
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "videoUrl",
              "name": "videoUrl",
              "type": "string",
              "value": "https://www.youtube.com/watch?v=REPLACE_VIDEO_ID"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "validate-input",
      "name": "Validate input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        240
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const value = $('Configure input').first().json.videoUrl;\nif (typeof value !== 'string' || value.includes('REPLACE_')) throw new Error('Set videoUrl to a public YouTube watch or Shorts URL with available captions.');\nif (!/^https:\\/\\/(?:www\\.)?(?:youtube\\.com\\/(?:watch\\?[^\\s]+|shorts\\/[A-Za-z0-9_-]+(?:[?/#][^\\s]*)?)|youtu\\.be\\/[A-Za-z0-9_-]+(?:[?/#][^\\s]*)?)$/.test(value)) throw new Error('Use a public HTTPS YouTube watch or Shorts URL.');\nreturn [{ json: { videoUrl: value } }];"
      }
    },
    {
      "id": "fetch-transcript",
      "name": "Fetch transcript",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        720,
        240
      ],
      "parameters": {
        "method": "GET",
        "url": "https://api.fetchfox.net/youtube/transcript",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $('Configure input').first().json.videoUrl }}"
            }
          ]
        },
        "options": {
          "timeout": 180000,
          "redirect": {
            "redirect": {
              "followRedirects": false
            }
          },
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": false,
              "responseFormat": "json"
            }
          }
        }
      },
      "retryOnFail": false
    },
    {
      "id": "transcript-output",
      "name": "Transcript output",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        240
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const response = $input.first().json;\nif (response.statusCode !== 200 || response.body?.success !== true || !response.body.data) throw new Error('FetchFox did not return a successful result. Inspect the HTTP node; correct input/authentication, wait for Retry-After on 429, or check your credits before rerunning.');\n\nconst data = response.body.data;\nif (typeof data.transcript !== 'string' || !Array.isArray(data.transcriptSegments)) throw new Error('Expected transcript text and timestamped segments.');\nreturn [{ json: { sourceUrl: $('Configure input').first().json.videoUrl, retrievedAt: new Date().toISOString(), transcript: data.transcript, transcriptSegments: data.transcriptSegments, creditsUsed: Number(response.headers?.['x-credits-used'] || 0) } }];"
      }
    },
    {
      "id": "setup-and-credit-cost",
      "name": "Setup and credit cost",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        240,
        240
      ],
      "parameters": {
        "content": "## FetchFox starter v1\n\n1. Edit Configure input.\n2. Create an n8n Header Auth credential: name x-access-key, value your FetchFox key. Select it in every Fetch node.\n3. Execute manually.\n\nOne successful transcript request costs 1 credit. Failed processing uses no credits.\n\nNo schedules or automatic retries. No credentials are included. Keep keys in n8n credentials. Source data can be partial or cached.",
        "width": 540,
        "height": 280
      }
    }
  ],
  "connections": {
    "Manual run": {
      "main": [
        [
          {
            "node": "Configure input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure input": {
      "main": [
        [
          {
            "node": "Validate input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate input": {
      "main": [
        [
          {
            "node": "Fetch transcript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch transcript": {
      "main": [
        [
          {
            "node": "Transcript output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "executionTimeout": 600,
    "timezone": "UTC",
    "saveDataSuccessExecution": "none",
    "saveDataErrorExecution": "none",
    "saveManualExecutions": false
  },
  "pinData": {},
  "tags": []
}
