{
  "name": "MADIAD Hub - Reconcile posts still in flight",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 10
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -160,
        0
      ],
      "id": "Every 10 minutes",
      "name": "Every 10 minutes"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": "[MADIAD Template] Publishing Schedule"
        },
        "sheetName": {
          "__rl": true,
          "value": "Schedule",
          "mode": "name"
        },
        "options": {
          "dataLocationOnSheet": {
            "values": {
              "rangeDefinition": "specifyRange",
              "headerRow": 1,
              "firstDataRow": 3
            }
          }
        }
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        60,
        0
      ],
      "id": "Read Schedule",
      "name": "Read Schedule"
    },
    {
      "parameters": {
        "jsCode": "\nconst out = [];\nfor (const it of $input.all()) {\n  const r = it.json;\n  if (String(r['Status'] ?? '').trim() !== 'Publishing') continue;\n  const rid = String(r['Request ID'] ?? '').trim();\n  if (!rid) continue;\n  out.push({ json: { _row: r.row_number, _rid: rid } });\n}\nreturn out;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        280,
        0
      ],
      "id": "Rows still waiting",
      "name": "Rows still waiting"
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.madiad.com/v1/posts/status?request_id={{ $json._rid }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Madiad-Source",
              "value": "tpl-reconcile-v1"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        500,
        0
      ],
      "id": "Check status",
      "name": "Check status",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "\n// Failure is success === false. MISSING INFORMATION IS NOT FAILURE: treating absence as failure reports errors for posts that published perfectly well.\n// No URL does NOT mean not finished. Telegram, Discord and listmonk return no link even after publishing.\nconst b = $json.body ?? {};\nconst row = $('Rows still waiting').item.json._row;\nconst res = b.results ?? {};\nconst lines = Object.entries(res).map(([k, v]) => {\n  if (v?.success === false) return k + ': failed, ' + (v?.error ?? 'no reason given');\n  if (v?.url) return k + ': ' + v.url;\n  if (v?.success === true) return k + ': published' + (v?.publish_id ? ' (' + v.publish_id + ')' : '');\n  return k + ': in progress';\n});\nconst bad = Object.entries(res).filter(([, v]) => v?.success === false)\n  .map(([k, v]) => k + ': ' + (v?.error ?? 'no reason given'));\nconst ids = Object.entries(res).filter(([, v]) => v?.publish_id)\n  .map(([k, v]) => k + '=' + v.publish_id).join(';');\nconst st = String(b.status ?? '');\nif (st === 'completed' || st === 'partial')\n  return [{ json: { _row: row, _st: 'Published', _link: lines.join('\\n'), _err: bad.join('\\n'), _ids: ids } }];\nif (st === 'failed')\n  return [{ json: { _row: row, _st: 'Error', _link: lines.join('\\n'), _err: bad.join('\\n') || 'The platform refused this post.', _ids: ids } }];\nreturn [];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        0
      ],
      "id": "Read the result",
      "name": "Read the result"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": "[MADIAD Template] Publishing Schedule"
        },
        "sheetName": {
          "__rl": true,
          "value": "Schedule",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "row_number": "={{ $json._row }}",
            "Status": "={{ $json._st }}",
            "Post Link": "={{ $json._link }}",
            "Platform Post IDs": "={{ $json._ids }}",
            "Error": "={{ $json._err }}",
            "Published At": "={{ $now.setZone('UTC').toFormat('yyyy-MM-dd HH:mm') }}"
          },
          "matchingColumns": [
            "row_number"
          ],
          "schema": []
        },
        "options": {
          "dataLocationOnSheet": {
            "values": {
              "rangeDefinition": "specifyRange",
              "headerRow": 1,
              "firstDataRow": 3
            }
          }
        }
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        940,
        0
      ],
      "id": "Update the row",
      "name": "Update the row",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "content": "## MADIAD Hub - Reconcile posts still in flight\n\nNo URL does NOT mean not finished. Telegram, Discord and listmonk return no link even after publishing.\n\nFailure is success === false. MISSING INFORMATION IS NOT FAILURE: treating absence as failure reports errors for posts that published perfectly well.",
        "height": 340,
        "width": 430,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -620,
        -180
      ],
      "id": "Setup",
      "name": "Setup"
    }
  ],
  "connections": {
    "Every 10 minutes": {
      "main": [
        [
          {
            "node": "Read Schedule",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Schedule": {
      "main": [
        [
          {
            "node": "Rows still waiting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rows still waiting": {
      "main": [
        [
          {
            "node": "Check status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check status": {
      "main": [
        [
          {
            "node": "Read the result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read the result": {
      "main": [
        [
          {
            "node": "Update the row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false
  }
}