{
  "name": "Mannequin or flat-lay clothing photo to on-model product clip with Sisif",
  "nodes": [
    {
      "id": "ff180106-1fec-4cc7-b488-8ac729f11aff",
      "name": "Setup Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1500,
        -700
      ],
      "parameters": {
        "content": "## Turn mannequin or flat-lay clothing photos into on-model product clips with Sisif\n\n### Who it's for\nFashion brands, resellers and marketplace sellers who shoot garments on a mannequin or flat-lay and want an on-model motion clip for each item, at $1 per 5-second clip.\n\n### How it works\n1. **Google Drive Trigger** watches a folder for new files.\n2. Non-image files are ignored.\n3. The photo is downloaded and converted to a base64 data URL.\n4. **Sisif** animates it with an apparel prompt that puts the garment on a model (5-second portrait MP4).\n5. The workflow polls every 30 s until the clip is `READY`, `ERROR` or `REFUNDED`, for at most 40 checks.\n6. A row with the file name, Sisif video ID, status, video URL and any error is appended to Google Sheets (status `TIMEOUT` if it never finished).\n\n### Setup\n1. Create a Sisif API key at https://sisif.ai/users/api-keys/ and add it in n8n as a **Bearer Auth** credential. Select it on **Generate On-Model Clip** and **Check Video Status**.\n2. Add a Google Drive credential, then pick the folder to watch in **Google Drive Trigger**.\n3. Create a Google Sheet with the headers: `file_name`, `drive_file_id`, `sisif_video_id`, `status`, `video_url`, `poster_url`, `error_message`, `processed_at`. Select it in both Sheets nodes.\n4. Optionally edit the prompt in **Apparel Prompt Config**.\n5. Drop a test photo into the folder, check the row, then activate.\n\n### Customize\n- Change model look, setting or movement in **Apparel Prompt Config**.\n- Change the poll interval in **Wait 30s**.",
        "width": 620,
        "height": 900
      }
    },
    {
      "id": "05b93149-eed8-4147-bf33-7d8eb5309e2b",
      "name": "Note: Prompt",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -300
      ],
      "parameters": {
        "content": "### Apparel prompt\nEdit `apparel_prompt` in **Apparel Prompt Config**. Describe the model, pose, setting and camera move. Keep the garment's color, pattern and details unchanged.",
        "width": 420,
        "height": 180,
        "color": 7
      }
    },
    {
      "id": "851a1798-ba9c-42ff-a939-9fcfbd73db54",
      "name": "Note: Render Loop",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        380,
        -300
      ],
      "parameters": {
        "content": "### Sisif render loop\nThe photo is sent in `image` as a base64 data URL (`data:image/...;base64,...`). Sisif fixes duration and resolution for photo clips. The loop checks `/api/videos/{id}/status/` every 30 s: `READY` writes a success row, `ERROR`/`REFUNDED` writes a failure row with Sisif's `error_message` (failed renders return the credits), and after 40 checks it writes a `TIMEOUT` row.",
        "width": 880,
        "height": 180,
        "color": 7
      }
    },
    {
      "id": "9a5d9348-8dba-4c23-9d4a-a53187a87aa5",
      "name": "Google Drive Trigger",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "typeVersion": 1,
      "position": [
        -840,
        0
      ],
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "event": "fileCreated",
        "options": {}
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "",
          "name": "Google Drive account"
        }
      }
    },
    {
      "id": "7a09631a-6238-4c5f-b918-52a02084b63d",
      "name": "Is Image File?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        -640,
        0
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.mimeType }}",
              "operation": "startsWith",
              "value2": "image/"
            }
          ]
        }
      }
    },
    {
      "id": "1f7371c6-bb9e-4503-a140-84005c9356ff",
      "name": "Download Photo",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -440,
        0
      ],
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {}
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "",
          "name": "Google Drive account"
        }
      }
    },
    {
      "id": "4819e12f-1a5a-43be-ad98-659565718b19",
      "name": "Photo to Base64",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        -240,
        0
      ],
      "parameters": {
        "operation": "binaryToPropery",
        "destinationKey": "image_base64",
        "options": {}
      }
    },
    {
      "id": "b7111987-4d1b-410c-9764-d6f1de96b4b6",
      "name": "Apparel Prompt Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -40,
        0
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "14529f76-3191-4e02-ac99-fe286bc9e044",
              "name": "apparel_prompt",
              "value": "A professional fashion model wearing exactly this garment, same color, fabric, pattern and details, standing in a bright minimal studio. The model turns slightly and takes a relaxed step toward the camera while the fabric moves naturally. Slow camera push-in, soft even lighting, e-commerce lookbook style.",
              "type": "string"
            },
            {
              "id": "3f77dbc7-8db7-4196-892e-5598199e5e90",
              "name": "image_base64",
              "value": "={{ $json.image_base64 }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "7309a060-7760-4f49-9e79-705c474091b3",
      "name": "Generate On-Model Clip",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        180,
        0
      ],
      "parameters": {
        "url": "https://sisif.ai/api/videos/generate/",
        "method": "POST",
        "sendBody": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "bodyParameters": {
          "parameters": [
            {
              "name": "prompt",
              "value": "={{ $json.apparel_prompt }}"
            },
            {
              "name": "image",
              "value": "=data:{{ $('Download Photo').item.binary.data.mimeType || 'image/jpeg' }};base64,{{ $json.image_base64 }}"
            }
          ]
        },
        "options": {}
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "",
          "name": "Sisif API (Bearer)"
        }
      }
    },
    {
      "id": "bcdddf05-8bc2-4c01-86a2-7f61b9c36fad",
      "name": "Wait 30s",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        400,
        0
      ],
      "parameters": {
        "amount": 30,
        "unit": "seconds"
      },
      "webhookId": "df6f7120-038b-486f-abfb-94c68fe08751"
    },
    {
      "id": "44e95e26-791a-4231-ba38-af9ade23792b",
      "name": "Check Video Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        620,
        0
      ],
      "parameters": {
        "url": "=https://sisif.ai/api/videos/{{ $json.id }}/status/",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "credentials": {
        "httpBearerAuth": {
          "id": "",
          "name": "Sisif API (Bearer)"
        }
      }
    },
    {
      "id": "4b940174-fd02-4dc4-831c-650d073ec262",
      "name": "Video Ready?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        840,
        0
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.status }}",
              "value2": "READY"
            }
          ]
        }
      }
    },
    {
      "id": "0c4e6fe1-46f0-4471-b8fe-098b7b426583",
      "name": "Render Failed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1060,
        160
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.status }}",
              "value2": "^(ERROR|REFUNDED)$",
              "operation": "regex"
            }
          ]
        }
      }
    },
    {
      "id": "c3f97373-5708-4998-a519-364968c3e48e",
      "name": "Log Clip to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1060,
        -100
      ],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "file_name": "={{ $('Google Drive Trigger').item.json.name }}",
            "drive_file_id": "={{ $('Google Drive Trigger').item.json.id }}",
            "sisif_video_id": "={{ $json.id }}",
            "status": "={{ $json.status }}",
            "video_url": "={{ $json.video_url || '' }}",
            "poster_url": "={{ $json.poster_url || '' }}",
            "error_message": "={{ $json.error_message || '' }}",
            "processed_at": "={{ $now.toISO() }}"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "id": "5b6beb6e-711a-45ea-9a97-eccfa2a54ab4",
      "name": "Log Failure to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1340,
        180
      ],
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "file_name": "={{ $('Google Drive Trigger').item.json.name }}",
            "drive_file_id": "={{ $('Google Drive Trigger').item.json.id }}",
            "sisif_video_id": "={{ $json.id }}",
            "status": "={{ $json.status }}",
            "video_url": "={{ $json.video_url || '' }}",
            "poster_url": "={{ $json.poster_url || '' }}",
            "error_message": "={{ $json.error_message || '' }}",
            "processed_at": "={{ $now.toISO() }}"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "id": "360f1926-59de-4b9f-b16a-793b361a000b",
      "name": "Max Attempts Reached?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        900,
        180
      ],
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $runIndex + 1 }}",
              "operation": "largerEqual",
              "value2": 40
            }
          ]
        }
      }
    },
    {
      "id": "45202ad3-7e3a-48f4-a475-fe169d95bd9c",
      "name": "Mark Timed Out",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1120,
        300
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a8109887-44b1-4277-ab5c-fd5ce7055ec8",
              "name": "status",
              "value": "TIMEOUT",
              "type": "string"
            },
            {
              "id": "4dc81b1d-6076-48e7-bd93-132623cb59a9",
              "name": "error_message",
              "value": "Clip not ready after 40 status checks (about 20 minutes)",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      }
    }
  ],
  "connections": {
    "Google Drive Trigger": {
      "main": [
        [
          {
            "node": "Is Image File?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Image File?": {
      "main": [
        [
          {
            "node": "Download Photo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Photo": {
      "main": [
        [
          {
            "node": "Photo to Base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Photo to Base64": {
      "main": [
        [
          {
            "node": "Apparel Prompt Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apparel Prompt Config": {
      "main": [
        [
          {
            "node": "Generate On-Model Clip",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate On-Model Clip": {
      "main": [
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 30s": {
      "main": [
        [
          {
            "node": "Check Video Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Video Status": {
      "main": [
        [
          {
            "node": "Video Ready?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Ready?": {
      "main": [
        [
          {
            "node": "Log Clip to Sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Render Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Render Failed?": {
      "main": [
        [
          {
            "node": "Log Failure to Sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Max Attempts Reached?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Max Attempts Reached?": {
      "main": [
        [
          {
            "node": "Mark Timed Out",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 30s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Timed Out": {
      "main": [
        [
          {
            "node": "Log Failure to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  }
}