{
  "name": "Publish from any system via webhook",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "postsider-publish",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "a6b7c8d9-0001-4a5b-9c0d-111111111111",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "webhookId": "postsider-publish"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// The webhook accepts JSON like:\n// {\n//   \"content\": \"Hello from my CRM!\",\n//   \"channelId\": \"REPLACE_WITH_CHANNEL_ID\",\n//   \"platform\": \"x\",                 // optional, defaults to 'x'\n//   \"date\": \"2026-08-16T10:00:00.000Z\" // optional; omit to publish immediately\n// }\nconst body = $input.first().json;\n\nreturn [{\n  json: {\n    content: body.content,\n    channelId: body.channelId,\n    platform: body.platform || 'x',\n    date: body.date || ''\n  }\n}];"
      },
      "id": "a6b7c8d9-0002-4a5b-9c0d-222222222222",
      "name": "1. Normalize payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "a6b7c8d9-0003-4a5b-9c0d-333333333333",
              "leftValue": "={{ $json.date }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "name": "filter.operator.notEmpty"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "a6b7c8d9-0004-4a5b-9c0d-444444444444",
      "name": "2. Date provided?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const item = $input.first().json;\nreturn [{\n  json: {\n    body: {\n      type: 'schedule',\n      date: item.date,\n      shortLink: false,\n      tags: [],\n      posts: [{\n        integration: { id: item.channelId },\n        value: [{ content: item.content, image: [] }],\n        settings: { __type: item.platform }\n      }]\n    }\n  }\n}];"
      },
      "id": "a6b7c8d9-0005-4a5b-9c0d-555555555555",
      "name": "3a. Build schedule payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        -160
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const item = $input.first().json;\nreturn [{\n  json: {\n    body: {\n      type: 'now',\n      date: '',\n      shortLink: false,\n      tags: [],\n      posts: [{\n        integration: { id: item.channelId },\n        value: [{ content: item.content, image: [] }],\n        settings: { __type: item.platform }\n      }]\n    }\n  }\n}];"
      },
      "id": "a6b7c8d9-0006-4a5b-9c0d-666666666666",
      "name": "3b. Build publish-now payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        160
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.postsider.com/public/v1/posts",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}"
      },
      "id": "a6b7c8d9-0007-4a5b-9c0d-777777777777",
      "name": "4a. Schedule in PostSider",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        -160
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.postsider.com/public/v1/posts",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}"
      },
      "id": "a6b7c8d9-0008-4a5b-9c0d-888888888888",
      "name": "4b. Publish now in PostSider",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        160
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "height": 340,
        "width": 460,
        "content": "SETUP (once):\n\n1. Create an API key in PostSider: app.postsider.com > Settings > API. It starts with ps_.\n2. In n8n create a Header Auth credential: Name = Authorization, Value = your ps_ key. Select it on both '4a.' and '4b.' nodes.\n3. Activate the workflow, then copy the webhook URL from the 'Webhook' node.\n\nCall it from anywhere: Zapier, Make, your own backend, a CRM button. POST JSON with content + channelId (+ optional platform and date). No date = publishes immediately; with a date = schedules.\n\nRetry safety: to avoid duplicates on retries, add an Idempotency-Key header to the POST /posts call (see docs.postsider.com/api). Self-hosted PostSider? Replace api.postsider.com with your domain (add /api if needed).",
        "color": 3
      },
      "id": "a6b7c8d9-0009-4a5b-9c0d-999999999999",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -360
      ]
    },
    {
      "parameters": {
        "content": "SETUP STEP BY STEP\nFollow in order. Do this once per workflow.\n\nSTEP 1 - Create the n8n credential (Header Auth, do this once):\n  \"PostSider API Key\": Name = Authorization, Value = your ps_ key (app.postsider.com > Settings > API > Create key).\n\nSTEP 2 - Activate the Webhook:\n  Activate this workflow (toggle Active). The \"Webhook\" node shows a URL that any system can call: Zapier, Make, your backend, a CRM button.\n\nSTEP 3 - Select the \"PostSider API Key\" credential on:\n  - \"4a. Schedule in PostSider\"\n  - \"4b. Publish now in PostSider\"\n\nSTEP 4 - Call the webhook:\n  POST JSON to the webhook URL with: text, channelId, and optionally a date (UTC ISO) to schedule. Without a date it publishes immediately.\n\nNOTE\nThe caller should supply an Idempotency-Key header for safe retries. Self-hosted PostSider? Replace api.postsider.com with your domain (add /api if your install serves the API under /api).",
        "height": 620,
        "width": 640,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -700
      ],
      "id": "setup-step-webhook-publish",
      "name": "Setup step by step"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "1. Normalize payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Normalize payload": {
      "main": [
        [
          {
            "node": "2. Date provided?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Date provided?": {
      "main": [
        [
          {
            "node": "3a. Build schedule payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "3b. Build publish-now payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3a. Build schedule payload": {
      "main": [
        [
          {
            "node": "4a. Schedule in PostSider",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3b. Build publish-now payload": {
      "main": [
        [
          {
            "node": "4b. Publish now in PostSider",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}