{
  "name": "Havis AI - GPT Image 2",
  "nodes": [
    {
      "id": "64086149-8aa6-492a-a86a-9406caadc7f7",
      "name": "Sticky Note - Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        896
      ],
      "parameters": {
        "width": 512,
        "height": 848,
        "content": "## Havis AI - GPT Image 2\n\n### How it works\n\n1. The workflow shows a public n8n form for collecting a GPT Image 2 request and a Havis API key.\n2. It converts the form values into the JSON payload expected by the Havis API.\n3. It submits the job to `https://havis.ai/api/gpt-image-2` and receives a task ID.\n4. It polls `https://havis.ai/api/task/{task_id}` until the job finishes or fails.\n5. It returns the task metadata, credit usage, payload, and generated result URLs.\n\n### Setup steps\n\n- [ ] Create a Havis API key at https://havis.ai/manager/profile.\n- [ ] Open the form trigger URL after importing this workflow into n8n.\n- [ ] Enter the required GPT Image 2 inputs: prompt, mode, aspect_ratio, resolution, image_url_1, image_url_2.\n- [ ] Confirm your Havis account has enough credits before running the workflow.\n- [ ] Adjust the polling wait time if your executions need faster or slower status checks.\n\n### Customization\n\nChange default prompt values, optional fields, polling interval, or the final output fields to match your automation. Keep the Havis domain fixed unless you intentionally publish a separate private workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "e1584196-423c-4579-a90b-69e3051d8f82",
      "name": "Sticky Note - Request Input",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        448,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 384,
        "content": "## Collect request inputs\n\nThe form trigger captures the Havis API key plus the GPT Image 2 inputs from the user.\n\nKey fields: prompt, mode, aspect_ratio, resolution, image_url_1, image_url_2, image_url_3, image_url_4, ...."
      },
      "typeVersion": 1
    },
    {
      "id": "8250a304-aa6f-4308-83ab-746044daab2a",
      "name": "Sticky Note - Payload Preparation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 384,
        "content": "## Build API payload\n\nThe code node trims blank values, applies default options, and builds a clean JSON body. Optional images, video URLs, audio URLs, tags, modes, or resolution fields are only included when provided."
      },
      "typeVersion": 1
    },
    {
      "id": "7a6aeef5-60a7-44a9-97db-dba668883bdb",
      "name": "Sticky Note - API Submission",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 384,
        "content": "## Submit generation job\n\nThe HTTP request sends the prepared payload to Havis AI with a bearer token. A successful response should include a `task_id` and the number of credits used for the request."
      },
      "typeVersion": 1
    },
    {
      "id": "c3cf173d-d737-4721-8ba6-b1483f272fa2",
      "name": "Sticky Note - Polling and Output",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1696,
        832
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 720,
        "content": "## Poll and return result\n\nThe workflow waits, checks task status, branches on completed or failed states, and loops while the job is still processing. Completed runs return result URLs; failed runs return a readable error object."
      },
      "typeVersion": 1
    },
    {
      "id": "55f79ab0-f0b2-2d66-30d7-188c5ad457ea",
      "name": "Form - GPT Image 2",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        520,
        1120
      ],
      "parameters": {
        "options": {},
        "formTitle": "Havis AI - GPT Image 2",
        "formFields": {
          "values": [
            {
              "fieldLabel": "api_key",
              "placeholder": "YOUR_HAVIS_API_KEY",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "prompt",
              "placeholder": "A cinematic fashion portrait with soft studio lighting",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "mode [optional]",
              "fieldOptions": {
                "values": [
                  {
                    "option": "text-to-image"
                  },
                  {
                    "option": "image-to-image"
                  }
                ]
              }
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "aspect_ratio [optional]",
              "fieldOptions": {
                "values": [
                  {
                    "option": "auto"
                  },
                  {
                    "option": "1:1"
                  },
                  {
                    "option": "4:3"
                  },
                  {
                    "option": "3:4"
                  },
                  {
                    "option": "16:9"
                  },
                  {
                    "option": "9:16"
                  }
                ]
              }
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "resolution [optional]",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1K"
                  },
                  {
                    "option": "2K"
                  },
                  {
                    "option": "4K"
                  }
                ]
              }
            },
            {
              "fieldLabel": "image_url_1 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_2 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_3 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_4 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_5 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_6 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_7 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "image_url_8 [optional]",
              "placeholder": "https://example.com/reference-product.jpg"
            },
            {
              "fieldLabel": "tag [optional]",
              "placeholder": "n8n-gpt-image-2"
            }
          ]
        },
        "formDescription": "Submit a GPT Image 2 job through Havis AI and poll until it completes."
      },
      "typeVersion": 2.2
    },
    {
      "id": "1d47d384-b80a-0229-2504-8497c4319a5c",
      "name": "Build Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        920,
        1120
      ],
      "parameters": {
        "jsCode": "const input = $json;\nconst clean = (value) => value === undefined || value === null ? '' : String(value).trim();\nconst body = {};\nconst apiKey = clean(input.api_key);\nfunction put(name, label, type, required) {\n  const value = clean(input[label]);\n  if (!value && !required) return;\n  if (type === \"number\") { const n = Number(value); if (!Number.isNaN(n)) body[name] = n; return; }\n  if (type === \"boolean\") { body[name] = value === \"true\" || value === \"1\" || value.toLowerCase() === \"yes\"; return; }\n  body[name] = value;\n}\nput(\"prompt\", \"prompt\", \"string\", true);\nput(\"mode\", \"mode [optional]\", \"string\", false);\nput(\"aspect_ratio\", \"aspect_ratio [optional]\", \"string\", false);\nput(\"resolution\", \"resolution [optional]\", \"string\", false);\nif (body[\"mode\"] === undefined || body[\"mode\"] === '') body[\"mode\"] = \"text-to-image\";\nif (body[\"aspect_ratio\"] === undefined || body[\"aspect_ratio\"] === '') body[\"aspect_ratio\"] = \"auto\";\nif (body[\"resolution\"] === undefined || body[\"resolution\"] === '') body[\"resolution\"] = \"1K\";\nconst arr0 = [\"image_url_1 [optional]\",\"image_url_2 [optional]\",\"image_url_3 [optional]\",\"image_url_4 [optional]\",\"image_url_5 [optional]\",\"image_url_6 [optional]\",\"image_url_7 [optional]\",\"image_url_8 [optional]\"].map(label => clean(input[label])).filter(Boolean);\nif (arr0.length) body[\"images\"] = arr0;\nbody.tag = clean(input['tag [optional]']) || \"n8n-gpt-image-2\";\nreturn [{ json: { api_key: apiKey, body } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1ea7811a-dc89-1105-11e8-d24081c55d60",
      "name": "Submit - Havis API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1320,
        1120
      ],
      "parameters": {
        "url": "https://havis.ai/api/gpt-image-2",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $json.body }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "1a8aca7d-b8c2-488f-0ee8-983447b40ef4",
      "name": "Wait 8s",
      "type": "n8n-nodes-base.wait",
      "position": [
        1520,
        1120
      ],
      "parameters": {
        "unit": "seconds",
        "amount": 8
      },
      "typeVersion": 1.1
    },
    {
      "id": "fdac0d2e-8d78-7154-5da1-3650ddda59e1",
      "name": "Check Task Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1720,
        1120
      ],
      "parameters": {
        "url": "={{ 'https://havis.ai/api/task/' + $('Submit - Havis API').first().json.task_id }}",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Build Payload').first().json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "a6dfcc04-c701-3d54-7f76-dae143107328",
      "name": "Is Completed?",
      "type": "n8n-nodes-base.if",
      "position": [
        1920,
        1120
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "04dfa4fe-25ce-88f0-ddc5-863e1dae3be3",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "5321c986-fbf8-71f9-deca-210166b8e17d",
      "name": "Is Failed?",
      "type": "n8n-nodes-base.if",
      "position": [
        2120,
        1240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d7a457f2-769a-1e83-f91f-7e4a06fbec29",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "failed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4b895656-ea13-1a88-99f7-e62263ef4c62",
      "name": "Wait 8s (loop)",
      "type": "n8n-nodes-base.wait",
      "position": [
        2320,
        1360
      ],
      "parameters": {
        "unit": "seconds",
        "amount": 8
      },
      "typeVersion": 1.1
    },
    {
      "id": "b5231133-519b-0250-e282-7f4e4ba3cd32",
      "name": "Return Result",
      "type": "n8n-nodes-base.set",
      "position": [
        2320,
        1040
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1426462c-8755-0255-97a9-7a50172038bd",
              "name": "task_id",
              "type": "string",
              "value": "={{ $('Submit - Havis API').first().json.task_id }}"
            },
            {
              "id": "13c4b339-9123-aabe-ec24-7af1a2a456ed",
              "name": "status",
              "type": "string",
              "value": "={{ $json.status }}"
            },
            {
              "id": "9e304776-6743-795b-19ae-f8f7f4655acf",
              "name": "model",
              "type": "string",
              "value": "={{ $json.model }}"
            },
            {
              "id": "923e2cd9-18fc-6799-c72d-c7f43d64de5f",
              "name": "result_urls",
              "type": "string",
              "value": "={{ JSON.stringify($json.result_urls || []) }}"
            },
            {
              "id": "334915e9-24af-b6c9-572f-e43a3ce37f65",
              "name": "credits_used",
              "type": "string",
              "value": "={{ $('Submit - Havis API').first().json.creditsUsed || $('Submit - Havis API').first().json.credits_used || '' }}"
            },
            {
              "id": "0e16f07c-baaf-b52a-9c3b-8dd332703d1c",
              "name": "submitted_payload",
              "type": "string",
              "value": "={{ JSON.stringify($('Build Payload').first().json.body) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f62aba9b-6421-c14e-f9e9-dc06b8d900d3",
      "name": "Return Error",
      "type": "n8n-nodes-base.set",
      "position": [
        2320,
        1200
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d70e0dfb-fd9f-eaef-64ed-2953bce724f0",
              "name": "task_id",
              "type": "string",
              "value": "={{ $('Submit - Havis API').first().json.task_id }}"
            },
            {
              "id": "27c338fc-2f78-013f-65f6-a035edc4d5c3",
              "name": "status",
              "type": "string",
              "value": "={{ $json.status }}"
            },
            {
              "id": "764fcebf-1906-d62f-f476-faa0d1da130a",
              "name": "model",
              "type": "string",
              "value": "={{ $json.model }}"
            },
            {
              "id": "c7b78fd5-508f-2a83-63d1-3f412f4203bc",
              "name": "error_message",
              "type": "string",
              "value": "={{ $json.error_message || $json.message || \"Generation failed\" }}"
            },
            {
              "id": "1ea0ca53-5fc3-6023-8db8-4c58ca9caf67",
              "name": "credits_used",
              "type": "string",
              "value": "={{ $('Submit - Havis API').first().json.creditsUsed || $('Submit - Havis API').first().json.credits_used || '' }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "connections": {
    "Wait 8s": {
      "main": [
        [
          {
            "node": "Check Task Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Failed?": {
      "main": [
        [
          {
            "node": "Return Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 8s (loop)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Payload": {
      "main": [
        [
          {
            "node": "Submit - Havis API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Completed?": {
      "main": [
        [
          {
            "node": "Return Result",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Is Failed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 8s (loop)": {
      "main": [
        [
          {
            "node": "Check Task Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Task Status": {
      "main": [
        [
          {
            "node": "Is Completed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Form - GPT Image 2": {
      "main": [
        [
          {
            "node": "Build Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit - Havis API": {
      "main": [
        [
          {
            "node": "Wait 8s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}