{
  "name": "Invoice Follow-up — Stripe Payment Confirmation (B)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "stripe-payment",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook-stripe-1",
      "name": "Webhook — Stripe Inbound",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract invoice_number from Stripe payload metadata\nconst body = $input.first().json.body || $input.first().json;\nconst eventType = body.type || 'unknown';\nconst paymentObj = body.data?.object || {};\nconst invoiceNumber = paymentObj.metadata?.invoice_number;\nconst amount = paymentObj.amount_received ? paymentObj.amount_received / 100 : null;\nconst currency = paymentObj.currency?.toUpperCase() || 'EUR';\n\nif (eventType !== 'payment_intent.succeeded') {\n  return { skip: true, reason: `Ignoring event type: ${eventType}` };\n}\n\nif (!invoiceNumber) {\n  throw new Error('Stripe payload missing metadata.invoice_number — caller must set this when creating the PaymentIntent.');\n}\n\nreturn { invoiceNumber, amount, currency, eventType };"
      },
      "id": "code-extract-1",
      "name": "Extract Payment Metadata",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE invoices SET status = 'paid', paid_at = NOW() WHERE invoice_number = $1 AND status != 'paid' RETURNING id, invoice_number, client_name, client_email, amount, currency, airtable_record_id",
        "options": {
          "queryReplacement": "={{ $json.invoiceNumber }}"
        }
      },
      "id": "pg-mark-paid-1",
      "name": "Postgres — Mark Paid",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.4,
      "position": [
        640,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "leftValue": "={{ $items().length }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "if-row-updated-1",
      "name": "IF — Row Updated?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        860,
        300
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "=https://api.airtable.com/v0/{{ $env.AIRTABLE_BASE_ID }}/{{ $env.AIRTABLE_TABLE_NAME }}/{{ $json.airtable_record_id }}",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ fields: { status: 'paid' } }) }}",
        "options": {}
      },
      "id": "airtable-paid-1",
      "name": "Airtable — Mark Paid",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1080,
        200
      ]
    },
    {
      "parameters": {
        "sendTo": "={{ $json.client_email }}",
        "subject": "=Payment received — Invoice {{ $json.invoice_number }}",
        "emailType": "text",
        "message": "=Hi {{ $json.client_name }},\n\nWe've received your payment for invoice {{ $json.invoice_number }} ({{ $json.currency }} {{ $json.amount }}). Thank you!\n\nLet me know if you need anything else.\n\nBest,\n{{ $env.OWNER_NAME }}\n{{ $env.BUSINESS_NAME }}",
        "options": {}
      },
      "id": "gmail-confirm-1",
      "name": "Gmail — Send Confirmation",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1300,
        200
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ received: true, updated: true }) }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "respond-200-ok-1",
      "name": "Respond — 200 OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1520,
        200
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ received: true, updated: false, reason: 'already_paid_or_unknown' }) }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "respond-200-noop-1",
      "name": "Respond — 200 No-op",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1080,
        400
      ]
    }
  ],
  "connections": {
    "Webhook — Stripe Inbound": {
      "main": [
        [
          {
            "node": "Extract Payment Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Payment Metadata": {
      "main": [
        [
          {
            "node": "Postgres — Mark Paid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres — Mark Paid": {
      "main": [
        [
          {
            "node": "IF — Row Updated?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF — Row Updated?": {
      "main": [
        [
          {
            "node": "Airtable — Mark Paid",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond — 200 No-op",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Airtable — Mark Paid": {
      "main": [
        [
          {
            "node": "Gmail — Send Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail — Send Confirmation": {
      "main": [
        [
          {
            "node": "Respond — 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
