{
  "name": "Route a post through approval",
  "nodes": [
    {
      "parameters": {},
      "id": "f5a6b7c8-0001-4a5b-9c0d-111111111111",
      "name": "When clicking 'Test workflow'",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Edit the values below, then run the workflow.\n// The draft is created WITH a date (from the best slot) so that once a human\n// approves it in the app, PostSider schedules it at that time automatically.\nconst channelId = 'REPLACE_WITH_CHANNEL_ID';\nconst platform = 'x';\nconst content = 'A draft waiting for a human yes. \u270d\ufe0f';\n\nreturn [{ json: { channelId, platform, content } }];"
      },
      "id": "f5a6b7c8-0002-4a5b-9c0d-222222222222",
      "name": "1. Post content",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.postsider.com/public/v1/find-slot/{{ $json.channelId }}"
      },
      "id": "f5a6b7c8-0003-4a5b-9c0d-333333333333",
      "name": "2. Find best slot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const input = $('1. Post content').first().json;\nconst slot = $input.first().json; // { date: '2026-08-16T10:00:00.000' } UTC, append 'Z'\n\nreturn [{\n  json: {\n    body: {\n      type: 'draft',\n      date: slot.date + 'Z',\n      shortLink: false,\n      tags: [],\n      posts: [{\n        integration: { id: input.channelId },\n        value: [{ content: input.content, image: [] }],\n        settings: { __type: input.platform }\n      }]\n    }\n  }\n}];"
      },
      "id": "f5a6b7c8-0004-4a5b-9c0d-444444444444",
      "name": "3. Build draft payload",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.postsider.com/public/v1/posts",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Idempotency-Key",
              "value": "=post-{{ $now.toISO() }}"
            }
          ]
        }
      },
      "id": "f5a6b7c8-0005-4a5b-9c0d-555555555555",
      "name": "4. Create draft",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// The create response is an array like [{ postId, integration }]; n8n splits it into items.\nreturn [{ json: { postId: $input.first().json.postId } }];"
      },
      "id": "f5a6b7c8-0006-4a5b-9c0d-666666666666",
      "name": "5. Extract post id",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.postsider.com/public/v1/posts/{{ $json.postId }}/request-approval"
      },
      "id": "f5a6b7c8-0007-4a5b-9c0d-777777777777",
      "name": "6. Request approval",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "resume": "timeInterval",
        "amount": 30,
        "unit": "minutes"
      },
      "id": "f5a6b7c8-0008-4a5b-9c0d-888888888888",
      "name": "7. Wait for review",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1540,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.postsider.com/public/v1/posts/{{ $json.postId }}/approval"
      },
      "id": "f5a6b7c8-0009-4a5b-9c0d-999999999999",
      "name": "8. Check approval status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1760,
        0
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "1",
          "name": "PostSider API Key"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "f5a6b7c8-000a-4a5b-9c0d-aaaaaaaaaaaa",
              "leftValue": "={{ $json.status }}",
              "rightValue": "APPROVED",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "f5a6b7c8-000b-4a5b-9c0d-bbbbbbbbbbbb",
      "name": "9. Approved?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1980,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const status = $input.first().json;\nreturn [{ json: { message: 'Approved. PostSider scheduled it at the chosen slot.', status } }];"
      },
      "id": "f5a6b7c8-000c-4a5b-9c0d-cccccccccccc",
      "name": "Approved",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2200,
        -160
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const status = $input.first().json;\nreturn [{ json: { message: 'Not approved yet (PENDING) or rejected. Check the approval queue in the app.', status } }];"
      },
      "id": "f5a6b7c8-000d-4a5b-9c0d-dddddddddddd",
      "name": "Not approved",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2200,
        160
      ]
    },
    {
      "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 every HTTP node here.\n3. Edit '1. Post content' with your channel id and text.\n\nHow it works: the workflow creates a DRAFT (with a date from the best slot), pushes it into the human approval queue, waits, then checks the outcome. When a team member approves in the app, PostSider schedules the draft automatically. Adjust '7. Wait for review' to your review cadence, or replace it with a Schedule Trigger to poll until resolved.\n\nSelf-hosted PostSider? Replace api.postsider.com with your domain (add /api if needed).",
        "color": 3
      },
      "id": "f5a6b7c8-000e-4a5b-9c0d-eeeeeeeeeeee",
      "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 - \"1. Post content\" (Set node):\n  Fill in: text (your post), channelId (a real channel id from app > Settings > Channels).\n\nSTEP 3 - Select the \"PostSider API Key\" credential on:\n  - \"2. Find best slot\"\n  - \"4. Create draft\"\n  - \"6. Request approval\"\n  - \"8. Check approval status\"\n\nSTEP 4 - Run:\n  Click \"Test workflow\" once. A draft is created at the best slot and pushed into the approval queue.\n\nSTEP 5 - Approve:\n  Approve the post in the app (the approval inbox). PostSider schedules it at the stored slot.\n\nNOTE\nSelf-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-approval-queue",
      "name": "Setup step by step"
    }
  ],
  "connections": {
    "When clicking 'Test workflow'": {
      "main": [
        [
          {
            "node": "1. Post content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Post content": {
      "main": [
        [
          {
            "node": "2. Find best slot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Find best slot": {
      "main": [
        [
          {
            "node": "3. Build draft payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Build draft payload": {
      "main": [
        [
          {
            "node": "4. Create draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. Create draft": {
      "main": [
        [
          {
            "node": "5. Extract post id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Extract post id": {
      "main": [
        [
          {
            "node": "6. Request approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. Request approval": {
      "main": [
        [
          {
            "node": "7. Wait for review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. Wait for review": {
      "main": [
        [
          {
            "node": "8. Check approval status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Check approval status": {
      "main": [
        [
          {
            "node": "9. Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9. Approved?": {
      "main": [
        [
          {
            "node": "Approved",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Not approved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}