{
  "name": "Wy\u015blij potwierdzenie zam\u00f3wienia z przyciskiem akcji Gmail (mailstack)",
  "nodes": [
    {
      "id": "webhook",
      "name": "Purchase webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        300
      ],
      "onError": "continueRegularOutput",
      "parameters": {
        "httpMethod": "POST",
        "path": "mailstack-purchase-confirmation",
        "responseMode": "lastNode",
        "options": {}
      }
    },
    {
      "id": "config",
      "name": "Configuration (EDIT ME)",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        300,
        300
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "baseUrl",
              "value": "https://mail.yourdomain.com",
              "type": "string"
            },
            {
              "id": "a2",
              "name": "apiKey",
              "value": "your-mailstack-api-key",
              "type": "string"
            },
            {
              "id": "a3",
              "name": "brand",
              "value": "acme",
              "type": "string"
            },
            {
              "id": "a4",
              "name": "to",
              "value": "={{ $json.body.customer.email }}",
              "type": "string"
            },
            {
              "id": "a5",
              "name": "name",
              "value": "={{ $json.body.customer.name }}",
              "type": "string"
            },
            {
              "id": "a6",
              "name": "amount",
              "value": "={{ $json.body.amount }}",
              "type": "string"
            },
            {
              "id": "a7",
              "name": "currency",
              "value": "={{ $json.body.currency }}",
              "type": "string"
            },
            {
              "id": "a8",
              "name": "item",
              "value": "={{ $json.body.product }}",
              "type": "string"
            },
            {
              "id": "a9",
              "name": "orderId",
              "value": "={{ $json.body.orderId }}",
              "type": "string"
            },
            {
              "id": "a10",
              "name": "orderUrl",
              "value": "={{ $json.body.orderUrl }}",
              "type": "string"
            },
            {
              "id": "a11",
              "name": "discountCode",
              "value": "",
              "type": "string"
            },
            {
              "id": "a12",
              "name": "discountDescription",
              "value": "10% off your next course",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": false,
        "options": {}
      }
    },
    {
      "id": "build",
      "name": "Build request body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        300
      ],
      "parameters": {
        "jsCode": "// Assemble the mailstack /v1/send body: a payment confirmation with a Gmail\n// action button, plus a discount badge IF a discount code was configured.\n// mailstack drops incomplete markup directives on its own (fail-soft), but we\n// only bother sending the discountOffer block at all when there's a code to show.\nconst c = $input.first().json;\nconst markup = [\n  { kind: 'viewAction', name: 'View order', url: c.orderUrl },\n];\nif (c.discountCode) {\n  markup.push({ kind: 'discountOffer', discountCode: c.discountCode, description: c.discountDescription });\n}\nconst body = {\n  brand: c.brand,\n  template: 'payment',\n  to: c.to,\n  name: c.name,\n  amount: c.amount,\n  currency: c.currency,\n  item: c.item,\n  orderId: c.orderId,\n  orderUrl: c.orderUrl,\n  markup,\n};\nreturn [{ json: { baseUrl: c.baseUrl, apiKey: c.apiKey, body } }];"
      }
    },
    {
      "id": "send",
      "name": "Send confirmation via mailstack",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        900,
        300
      ],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "POST",
        "url": "={{ $json.baseUrl }}/v1/send",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $json.apiKey }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "options": {}
      }
    },
    {
      "id": "st0",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -460
      ],
      "parameters": {
        "content": "## Zamie\u0144 webhook zam\u00f3wienia w branded mail potwierdzaj\u0105cy z przyciskiem akcji Gmail\n\nOdbiera webhook zam\u00f3wienia/zakupu (ze Stripe, Gumroad, WooCommerce, [Sellf](https://sellf.app) albo w\u0142asnego checkoutu) i wysy\u0142a kupuj\u0105cemu branded potwierdzenie przez [mailstack](https://github.com/jurczykpawel/mailstack) - darmowy, samodzielnie hostowany wysy\u0142acz maili. Mail niesie **markup schema.org**, wi\u0119c Gmail pokazuje prawdziwy przycisk akcji \"Zobacz zam\u00f3wienie\" na pasku wiadomo\u015bci oraz opcjonalny badge z kodem rabatowym w zak\u0142adce Oferty.\n\n### Jak to dzia\u0142a\n- **Purchase webhook** odbiera payload Twojego dostawcy (przyk\u0142ad zak\u0142ada og\u00f3lny kszta\u0142t `{customer:{email,name}, amount, currency, product, orderId, orderUrl}`).\n- **Configuration (EDIT ME)** mapuje te pola (dostosuj wyra\u017cenia do swojego dostawcy) plus dane po\u0142\u0105czenia z mailstackiem i opcjonalny kod rabatowy.\n- **Build request body** buduje `template: \"payment\"` oraz tablic\u0119 `markup`: `viewAction` (przycisk Gmail) i `discountOffer`. Mailstack automatycznie pomija blok rabatu, je\u015bli zostawisz `discountCode` puste - mail i tak wychodzi.\n- **HTTP Request** wysy\u0142a POST na `/v1/send` (tryb zaufany).\n\n### Konfiguracja\n1. Wdr\u00f3\u017c mailstack i utw\u00f3rz klucz API (patrz README).\n2. Wska\u017c webhook swojego dostawcy p\u0142atno\u015bci na Production URL tego workflowa, albo podmie\u0144 node **Purchase webhook** na natywny trigger dostawcy, je\u015bli taki ma.\n3. Dostosuj wyra\u017cenia w **Configuration (EDIT ME)** do nazw p\u00f3l w payloadzie Twojego dostawcy.\n4. Uzupe\u0142nij `baseUrl`, `apiKey`, `brand`; zostaw `discountCode` puste, \u017ceby wys\u0142a\u0107 zwyk\u0142e potwierdzenie.\n5. Aktywuj workflow.\n\n### Wskaz\u00f3wki\nAdnotacje mailstacka w zak\u0142adce Oferty (kody rabatowe, karty z obrazkiem) renderuj\u0105 si\u0119 dla dowolnych odbiorc\u00f3w dopiero po allowli\u015bcie domeny u Google - patrz README mailstacka. Przyciski akcji dzia\u0142aj\u0105 od razu, bez allowlisty.\n",
        "width": 1020,
        "height": 380,
        "color": 1
      }
    },
    {
      "id": "sec1",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        160
      ],
      "parameters": {
        "content": "## 1. Odbierz i zmapuj zam\u00f3wienie\nWebhook odbiera payload dostawcy; Configuration mapuje go na pola mailstacka.",
        "width": 480,
        "height": 420,
        "color": 7
      }
    },
    {
      "id": "sec2",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        560,
        160
      ],
      "parameters": {
        "content": "## 2. Zbuduj i wy\u015blij mail\nZ\u0142\u00f3\u017c mail payment z przyciskiem Gmail/markupem rabatu i wy\u015blij POST do mailstacka.",
        "width": 460,
        "height": 420,
        "color": 7
      }
    },
    {
      "id": "st1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -20,
        620
      ],
      "parameters": {
        "content": "## Zabezpiecz ten webhook przed produkcj\u0105\nKtokolwiek znajdzie ten URL, mo\u017ce wywo\u0142a\u0107 fa\u0142szywy mail potwierdzaj\u0105cy. Dodaj weryfikacj\u0119 podpisu swojego dostawcy (np. Stripe-Signature) przed Configuration, albo sprawdzenie wsp\u00f3\u0142dzielonego sekretu w nag\u0142\u00f3wku.",
        "width": 300,
        "height": 160,
        "color": 3
      }
    }
  ],
  "connections": {
    "Purchase webhook": {
      "main": [
        [
          {
            "node": "Configuration (EDIT ME)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configuration (EDIT ME)": {
      "main": [
        [
          {
            "node": "Build request body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build request body": {
      "main": [
        [
          {
            "node": "Send confirmation via mailstack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}