{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "984abb02-168c-4f0d-8b5f-c45e3c15358c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        -80
      ],
      "parameters": {
        "width": 416,
        "height": 252,
        "content": "### \u27281.  How To Get Started\n\n1. Double-click the **APImage API** node to open it.\n2. Replace \"_YOUR_API_KEY_\" with your API Key.\n3. Use the **Remove Background** node to submit a request.\n\n**Note:** You can find your API Key inside the Dashboard of your APImage account. \n\n\n[Open the Dashboard \ud83e\udc65](https://apimage.org/dashboard)"
      },
      "typeVersion": 1
    },
    {
      "id": "319e2532-7350-4f8c-9f76-1abed7a9481b",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 228,
        "content": "### \ud83e\udde9 3. How to Extend or Customize\n- **Input:** You can replace the data input to the APImage API node with any other node that provides the required parameters. Refer to the documentation to ensure you're passing all necessary values.\n\n- **Output:** After the APImage API node, feel free to add additional nodes to handle the output \u2014 for example, to download and store it in a database or cloud storage, send it via email, or integrate it with other software."
      },
      "typeVersion": 1
    },
    {
      "id": "a1ab1aa1-5b9f-4ec1-8ee1-ba0fcdbc3af2",
      "name": "Get a record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        288,
        304
      ],
      "parameters": {
        "id": "=",
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appYCwSqo6Q1lGUah",
          "cachedResultUrl": "https://airtable.com/appYCwSqo6Q1lGUah",
          "cachedResultName": "Creatives Library"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tblbA4dbCU9q6wQEw",
          "cachedResultUrl": "https://airtable.com/appYCwSqo6Q1lGUah/tblbA4dbCU9q6wQEw",
          "cachedResultName": "Media Files"
        },
        "options": {}
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "d2a9e1a0-4490-4f09-ad98-d72126ab346f",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        512,
        304
      ],
      "parameters": {
        "jsCode": "const inputData = $input.all();\nconst outputItems = [];\n\nfor (const item of inputData) {\n  if (item.json.records && Array.isArray(item.json.records)) {\n    \n    for (const record of item.json.records) {\n      if (record.fields?.Thumbnail?.[0]?.url) {\n        const thumbnail = record.fields.Thumbnail[0];\n        \n        // W\u00e4hle die beste Thumbnail-Qualit\u00e4t\n        let thumbnailUrl = thumbnail.url;\n        if (thumbnail.thumbnails?.large?.url) {\n          thumbnailUrl = thumbnail.thumbnails.large.url;\n        } else if (thumbnail.thumbnails?.full?.url) {\n          thumbnailUrl = thumbnail.thumbnails.full.url;\n        }\n        \n        outputItems.push({\n          json: {\n            // Original Record Info\n            recordId: record.id,\n            fileName: record.fields['File Name'] || 'Unknown',\n            mediaType: record.fields['Media Type'] || 'Unknown',\n            uploadDate: record.fields['Upload Date'],\n            fileSize: record.fields['File Size'],\n            \n            // Thumbnail Info\n            originalThumbnailUrl: thumbnailUrl,\n            thumbnailId: thumbnail.id,\n            \n            // Processing Status\n            step: 'ready_for_bg_removal',\n            processedAt: new Date().toISOString(),\n            \n            // F\u00fcr Dateiname-Generierung\n            cleanFileName: (record.fields['File Name'] || 'unknown')\n              .replace(/[^a-zA-Z0-9]/g, '_')\n              .toLowerCase()\n          }\n        });\n      }\n    }\n  }\n}\n\nconsole.log(`${outputItems.length} Thumbnails f\u00fcr Verarbeitung vorbereitet`);\nreturn outputItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "8c127d1b-b439-48b7-ad58-17ac9d9536af",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        736,
        304
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "originalThumbnailUrl"
      },
      "typeVersion": 1
    },
    {
      "id": "fa4b68bb-e223-4ca7-bc64-0b29929910e3",
      "name": "Download",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1184,
        304
      ],
      "parameters": {
        "url": "={{ $json.processed_image_url }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "018f9383-1384-4e75-ae59-f3c09865a7fe",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1408,
        304
      ],
      "parameters": {
        "name": "bg_removal",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "e7a3de31-993c-4fc4-b243-32b25c841878",
      "name": "APImage API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        960,
        304
      ],
      "parameters": {
        "url": "https://apimage.org/api/ai-remove-background",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "image_url",
              "value": "={{ $json.originalThumbnailUrl }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5a7ae8df-2f88-43c5-8b35-de50f8389276",
      "name": "Remove Background",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        64,
        304
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b13ebf15-d26d-4bbd-96f1-8be97ad0c9c3",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        192
      ],
      "parameters": {
        "color": 4,
        "width": 416,
        "height": 368,
        "content": "###  \u26a1 2. Core Functionality \n- Background Removal (APImage API node)\n- Store final image (Download node)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n**Note:** You can change the rest of this workflow, but these two components are essential to ensure the background removal works correctly and export the final images."
      },
      "typeVersion": 1
    },
    {
      "id": "583b449b-e849-43b6-9cbb-d6569b65f9a3",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        192
      ],
      "parameters": {
        "width": 880,
        "height": 368,
        "content": "### Customize this part\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n**Note:** You can modify, customize, or completely replace all nodes in this section. For instance, you can swap Airtable for any other data source that provides your image data (via URL)."
      },
      "typeVersion": 1
    },
    {
      "id": "33df6512-8693-4eee-9695-cb01e521aea7",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        192
      ],
      "parameters": {
        "width": 256,
        "height": 368,
        "content": "### Customize this part\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n**Note:** You can completely change or modify this part as well. "
      },
      "typeVersion": 1
    },
    {
      "id": "018cdce1-5705-41db-aa61-2d53ddf865a3",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        -176
      ],
      "parameters": {
        "width": 416,
        "height": 80,
        "content": "# Start here"
      },
      "typeVersion": 1
    },
    {
      "id": "83725205-b574-4066-8cfc-066b01abbab7",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 4576,
        "content": "### \ud83d\udcc3 4. Full Workflow Documentation\n\n### \ud83d\udfe2 Remove Background (Manual Trigger)\n**Purpose:** Starts the workflow manually when you want to process images.\n- Click this node to begin the background removal process\n- No configuration needed - just acts as the starting point\n- Triggers the entire workflow chain\n\n**\ud83d\udd27 Customization Options:**\n- Replace with **Schedule Trigger** for automatic processing (daily/weekly)\n- Replace with **Webhook Trigger** to start via API calls\n- Replace with **File Trigger** to process when new files are added\n\n---\n\n### \ud83d\udccb Get a Record (Airtable)\n**Purpose:** Retrieves media files from your Airtable \"Creatives Library\" database.\n- Connects to the \"Media Files\" table in your Airtable base\n- Fetches records containing image thumbnails that need background removal\n- Uses your configured Airtable credentials to access the data\n- Returns all matching records with their thumbnail URLs and metadata\n\n**\ud83d\udd27 Customization Options:**\n- **Change Data Source:** Replace with Google Sheets, Notion, or any database/storage node\n- **Add Filters:** Use \"Filter By Formula\" to process only specific records\n- **Different Tables:** Change to any table with image URLs\n- **Batch Processing:** Set \"Maximum number of records\" to limit processing\n\n---\n\n### \u2699\ufe0f Code (JavaScript Processing)\n**Purpose:** Processes the Airtable records and prepares thumbnail data for background removal.\n- Extracts thumbnail URLs from each Airtable record\n- Chooses the best quality thumbnail (large > full > original)\n- Creates clean filenames by removing special characters\n- Adds processing metadata and timestamps\n- Outputs one item per thumbnail ready for processing\n\n**\ud83d\udd27 Customization Options:**\n- **File Naming:** Modify the `cleanFileName` logic for custom naming patterns\n- **Quality Selection:** Change thumbnail quality preference order\n- **Add Validation:** Include image format/size checks before processing\n- **Metadata Fields:** Extract additional fields from your Airtable records\n- **Error Handling:** Add try/catch blocks for robust processing\n\n#### \ud83d\udccb Adapting to Different Airtable Databases\n\n**Current Code Structure (for reference):**\n```javascript\n// Current field mappings\nfileName: record.fields['File Name']\nmediaType: record.fields['Media Type']\nuploadDate: record.fields['Upload Date']\nfileSize: record.fields['File Size']\nthumbnailUrl: record.fields.Thumbnail[0].url\n```\n\n**\ud83d\udd04 Common Customizations for Different Databases:**\n\n**1. Different Image Field Names:**\n```javascript\n// If your image field is called \"Photo\" instead of \"Thumbnail\"\nif (record.fields?.Photo?.[0]?.url) {\n  const thumbnail = record.fields.Photo[0];\n  \n// If it's called \"Image\", \"Picture\", or \"Attachment\"\nif (record.fields?.Image?.[0]?.url) {\n  const thumbnail = record.fields.Image[0];\n```\n\n**2. Different Metadata Fields:**\n```javascript\n// Customize these field names to match your Airtable schema\nfileName: record.fields['Product Name'] || record.fields['Title'] || 'Unknown',\ncategory: record.fields['Category'] || record.fields['Type'],\nbrand: record.fields['Brand'] || record.fields['Company'],\nsku: record.fields['SKU'] || record.fields['Product ID'],\ndescription: record.fields['Description'] || record.fields['Notes'],\n```\n\n**3. Product Database Example:**\n```javascript\noutputItems.push({\n  json: {\n    // Product Info\n    recordId: record.id,\n    productName: record.fields['Product Name'] || 'Unknown',\n    sku: record.fields['SKU'],\n    category: record.fields['Category'],\n    brand: record.fields['Brand'],\n    price: record.fields['Price'],\n    \n    // Image Info\n    originalImageUrl: imageUrl,\n    imageId: image.id,\n    \n    // Processing Status\n    step: 'ready_for_bg_removal',\n    processedAt: new Date().toISOString(),\n    \n    // Clean filename from product name\n    cleanFileName: (record.fields['Product Name'] || 'unknown')\n      .replace(/[^a-zA-Z0-9]/g, '_')\n      .toLowerCase() + '_' + record.fields['SKU']\n  }\n});\n```\n\n**4. Portfolio/Gallery Database Example:**\n```javascript\noutputItems.push({\n  json: {\n    // Portfolio Info\n    recordId: record.id,\n    projectName: record.fields['Project Name'] || 'Unknown',\n    clientName: record.fields['Client'],\n    createdDate: record.fields['Created'],\n    tags: record.fields['Tags'],\n    \n    // Image Info\n    originalImageUrl: imageUrl,\n    imageId: image.id,\n    \n    // Processing Status\n    step: 'ready_for_bg_removal',\n    processedAt: new Date().toISOString(),\n    \n    // Clean filename from project and client\n    cleanFileName: `${record.fields['Client'] || 'client'}_${record.fields['Project Name'] || 'project'}`\n      .replace(/[^a-zA-Z0-9]/g, '_')\n      .toLowerCase()\n  }\n});\n```\n\n**5. Employee/Contact Database Example:**\n```javascript\noutputItems.push({\n  json: {\n    // Contact Info\n    recordId: record.id,\n    fullName: record.fields['Full Name'] || 'Unknown',\n    department: record.fields['Department'],\n    position: record.fields['Position'],\n    email: record.fields['Email'],\n    \n    // Image Info (headshot/profile photo)\n    originalImageUrl: imageUrl,\n    imageId: image.id,\n    \n    // Processing Status\n    step: 'ready_for_bg_removal',\n    processedAt: new Date().toISOString(),\n    \n    // Clean filename from name\n    cleanFileName: (record.fields['Full Name'] || 'employee')\n      .replace(/[^a-zA-Z0-9]/g, '_')\n      .toLowerCase() + '_headshot'\n  }\n});\n```\n\n**\ud83d\udd0d How to Identify Your Field Names:**\n1. In n8n, run just the \"Get a record\" node first\n2. Check the output data to see your exact field names\n3. Look for the structure: `record.fields['Your Field Name']`\n4. Update the Code node accordingly\n\n**\ud83d\udca1 Pro Tips:**\n- Always use optional chaining (`?.`) to prevent errors\n- Provide fallback values with `|| 'Default Value'`\n- Test with console.log() to debug field mappings\n- Use meaningful filenames that include key identifiers\n\n---\n\n### \ud83d\udd04 Split Out\n**Purpose:** Converts the array of thumbnails into individual items for parallel processing.\n- Takes the array of thumbnail data from the Code node\n- Splits each thumbnail into a separate workflow execution\n- Enables processing multiple images simultaneously\n- Each split item contains all the thumbnail metadata\n\n**\ud83d\udd27 Customization Options:**\n- **Batch Processing:** Replace with **Item Lists** node to process in batches\n- **Sequential Processing:** Remove this node to process all images as one batch\n- **Conditional Split:** Add **IF** node before this to filter which images to process\n\n---\n\n### \ud83e\udd16 APImage API (HTTP Request)\n**Purpose:** Calls the APImage service to remove backgrounds from thumbnails.\n- Sends POST request to APImage background removal API\n- Uses your API key for authentication (Bearer YOUR_TOKEN_HERE)\n- Passes the thumbnail URL as the image_url parameter\n- Returns the processed image URL without background\n\n---\n\n### \u2b07\ufe0f Download (HTTP Request)\n**Purpose:** Downloads the processed image from APImage's servers.\n- Fetches the background-removed image using the URL from APImage API\n- Downloads the actual image file data\n- Prepares the file for upload to Google Drive\n- No additional configuration needed\n\n**\ud83d\udd27 Customization Options:**\n- **File Format:** Add headers to specify PNG, JPG, or WebP format\n- **Image Processing:** Add **Sharp** node for resizing, compression, or format conversion\n- **Temporary Storage:** Save to local filesystem first with **Write Binary File**\n- **Quality Control:** Add image validation before proceeding\n\n---\n\n### \u2601\ufe0f Upload File (Google Drive)\n**Purpose:** Saves the processed images to your Google Drive.\n- Uploads the downloaded background-removed images\n- Saves files to the \"bg_removal\" folder in your Google Drive root\n- Uses your configured Google Drive credentials\n- Creates a permanent storage location for processed images\n\n**\ud83d\udd27 Customization Options:**\n- **Different Storage:** Replace with Dropbox, OneDrive, AWS S3, or FTP upload\n- **Folder Structure:** Create date-based folders or organize by project\n- **File Naming:** Use dynamic names with timestamps or original filenames\n- **Multiple Destinations:** Add parallel uploads to different services\n- **Metadata:** Set file descriptions, tags, or custom properties"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download": {
      "main": [
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "APImage API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "APImage API": {
      "main": [
        [
          {
            "node": "Download",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a record": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Background": {
      "main": [
        [
          {
            "node": "Get a record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}