{
  "name": "WF-04 · Proposal-to-Payment",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "call-ended",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "n1",
      "name": "Call Ended Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [200, 300],
      "webhookId": "call-ended-trigger",
      "notes": "Trigger from Calendly, Zoom, or your calendar app when a discovery/sales call ends. Payload should include: contact_name, contact_email, contact_company, meeting_id, meeting_title."
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "id": "1", "name": "contactName",    "value": "={{ $json.contact_name || $json.invitee_full_name || '' }}", "type": "string" },
            { "id": "2", "name": "contactEmail",   "value": "={{ $json.contact_email || $json.invitee_email || '' }}", "type": "string" },
            { "id": "3", "name": "contactCompany", "value": "={{ $json.contact_company || $json.company || '' }}", "type": "string" },
            { "id": "4", "name": "meetingId",      "value": "={{ $json.meeting_id || $json.event_id || '' }}", "type": "string" },
            { "id": "5", "name": "meetingTitle",   "value": "={{ $json.meeting_title || $json.event_name || 'Discovery Call' }}", "type": "string" },
            { "id": "6", "name": "calledAt",       "value": "={{ $now }}", "type": "string" }
          ]
        },
        "options": {}
      },
      "id": "n2",
      "name": "Parse Call Data",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [420, 300]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.fireflies.ai/graphql",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ FIREFLIES_API_KEY }}" },
            { "name": "Content-Type",  "value": "application/json" }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"query\": \"{ transcript(id: \\\"{{ $json.meetingId }}\\\") { title sentences { speaker_name raw_words } summary { action_items overview } } }\"\n}",
        "options": {},
        "notes": "Fetches the meeting transcript from Fireflies.ai. Replace with Otter.ai, Grain, or any transcription service API. Polling may be needed if transcript isn't ready instantly — add a Wait node + retry loop for production."
      },
      "id": "n3",
      "name": "Fetch Transcript",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [640, 300]
    },
    {
      "parameters": {
        "model": "gpt-4o",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a proposal writer for a professional services firm. Given a sales call transcript, extract the key details and draft a professional, concise proposal. Use the company's standard template tone: direct, specific, outcomes-first. No fluff."
            },
            {
              "role": "user",
              "content": "=Draft a proposal for {{ $('Parse Call Data').item.json.contactName }} at {{ $('Parse Call Data').item.json.contactCompany }}.\n\nTranscript summary:\n{{ $json.data.transcript.summary.overview }}\n\nAction items from the call:\n{{ $json.data.transcript.summary.action_items }}\n\nProposal should include:\n- Overview (2-3 sentences)\n- What's included (bullet list of deliverables)\n- Timeline\n- Next steps\n\nKeep it under 400 words. Use plain language."
            }
          ]
        },
        "options": {}
      },
      "id": "n4",
      "name": "Draft Proposal with AI",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1,
      "position": [860, 300],
      "credentials": {
        "openAiApi": { "id": "openai-creds", "name": "OpenAI" }
      }
    },
    {
      "parameters": {
        "sendTo": "{{ YOUR_EMAIL }}",
        "subject": "=Proposal draft ready — {{ $('Parse Call Data').item.json.contactCompany }}",
        "emailType": "html",
        "message": "=<p>Your proposal draft for <strong>{{ $('Parse Call Data').item.json.contactName }}</strong> at <strong>{{ $('Parse Call Data').item.json.contactCompany }}</strong> is ready for review.</p><hr><p>{{ $json.message.content.replace(/\\n/g, '<br>') }}</p><hr><p>Review, adjust as needed, then reply to this email with <strong>APPROVED</strong> to trigger the send. Or forward directly to the client and mark as approved manually.</p>",
        "options": {}
      },
      "id": "n5",
      "name": "Email Draft for Review",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [1080, 300],
      "credentials": {
        "gmailOAuth2": { "id": "gmail-creds", "name": "Gmail" }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "proposal-approved",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "n6",
      "name": "Approval Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [1080, 480],
      "webhookId": "proposal-approval",
      "notes": "Trigger this via a 'Mark Approved' button in your email client, a simple Airtable button, or a manual HTTP call. Payload: proposal_id, contact_email, proposal_text, deal_value."
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.docusign.com/v2.1/accounts/{{ DOCUSIGN_ACCOUNT_ID }}/envelopes",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ DOCUSIGN_ACCESS_TOKEN }}" },
            { "name": "Content-Type",  "value": "application/json" }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"emailSubject\": \"Please sign: {{ $('Parse Call Data').item.json.contactCompany }} engagement agreement\",\n  \"status\": \"sent\",\n  \"recipients\": {\n    \"signers\": [{\n      \"email\": \"{{ $('Parse Call Data').item.json.contactEmail }}\",\n      \"name\":  \"{{ $('Parse Call Data').item.json.contactName }}\",\n      \"recipientId\": \"1\",\n      \"routingOrder\": \"1\"\n    }]\n  },\n  \"documents\": [{\n    \"documentId\": \"1\",\n    \"name\": \"Engagement Agreement\",\n    \"fileExtension\": \"pdf\",\n    \"documentBase64\": \"{{ PROPOSAL_PDF_BASE64 }}\"\n  }]\n}",
        "options": {},
        "notes": "Replace with your e-sign provider (PandaDoc, Dropbox Sign, or DocuSign). For PandaDoc, the endpoint and payload structure will differ — see their API docs."
      },
      "id": "n7",
      "name": "Send for E-Sign",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [1300, 480]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "contract-signed",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "n8",
      "name": "Signature Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [1300, 640],
      "webhookId": "contract-signed",
      "notes": "DocuSign/PandaDoc posts to this URL when the document is signed."
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.stripe.com/v1/payment_links",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ STRIPE_SECRET_KEY }}" }
          ]
        },
        "sendBody": true,
        "specifyBody": "formUrlEncoded",
        "bodyParameters": {
          "parameters": [
            { "name": "line_items[0][price]",    "value": "{{ STRIPE_PRICE_ID }}" },
            { "name": "line_items[0][quantity]", "value": "1" }
          ]
        },
        "options": {},
        "notes": "Creates a Stripe payment link for the deposit. Replace STRIPE_PRICE_ID with your configured price ID, or create a price dynamically using the deal amount from the proposal."
      },
      "id": "n9",
      "name": "Create Invoice + Pay Link",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [1520, 640]
    },
    {
      "parameters": {
        "sendTo": "={{ $('Parse Call Data').item.json.contactEmail }}",
        "subject": "=You're all set — here's your invoice",
        "emailType": "html",
        "message": "=<p>Hi {{ $('Parse Call Data').item.json.contactName }},</p><p>Thanks for signing — we're excited to get started.</p><p>Your deposit invoice is ready: <a href=\"{{ $json.url }}\">Pay now →</a></p><p>Once received, I'll send over the kickoff details and calendar invite.</p><p>{{ YOUR_NAME }}<br>{{ YOUR_COMPANY }}</p>",
        "options": {}
      },
      "id": "n10",
      "name": "Send Invoice Email",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [1740, 640],
      "credentials": {
        "gmailOAuth2": { "id": "gmail-creds", "name": "Gmail" }
      }
    },
    {
      "parameters": {
        "calendar": "primary",
        "summary": "={{ $('Parse Call Data').item.json.contactCompany }} — Kickoff Call",
        "start": "={{ $now.plus({ days: 3 }).toISO() }}",
        "end":   "={{ $now.plus({ days: 3, hours: 1 }).toISO() }}",
        "additionalFields": {
          "description": "=Kickoff call with {{ $('Parse Call Data').item.json.contactName }}. Contract signed and deposit received.",
          "attendees": [{ "email": "={{ $('Parse Call Data').item.json.contactEmail }}" }],
          "sendUpdates": "all"
        }
      },
      "id": "n11",
      "name": "Schedule Kickoff",
      "type": "n8n-nodes-base.googleCalendar",
      "typeVersion": 1,
      "position": [1960, 640],
      "credentials": {
        "googleCalendarOAuth2Api": { "id": "gcal-creds", "name": "Google Calendar" }
      }
    }
  ],
  "connections": {
    "Call Ended Webhook":    { "main": [[{ "node": "Parse Call Data",          "type": "main", "index": 0 }]] },
    "Parse Call Data":       { "main": [[{ "node": "Fetch Transcript",         "type": "main", "index": 0 }]] },
    "Fetch Transcript":      { "main": [[{ "node": "Draft Proposal with AI",   "type": "main", "index": 0 }]] },
    "Draft Proposal with AI":{ "main": [[{ "node": "Email Draft for Review",   "type": "main", "index": 0 }]] },
    "Approval Webhook":      { "main": [[{ "node": "Send for E-Sign",          "type": "main", "index": 0 }]] },
    "Signature Webhook":     { "main": [[{ "node": "Create Invoice + Pay Link","type": "main", "index": 0 }]] },
    "Create Invoice + Pay Link":{ "main": [[{ "node": "Send Invoice Email",    "type": "main", "index": 0 }]] },
    "Send Invoice Email":    { "main": [[{ "node": "Schedule Kickoff",         "type": "main", "index": 0 }]] }
  },
  "active": false,
  "settings": { "executionOrder": "v1" },
  "id": "wf-04-proposal-to-payment",
  "versionId": "1.0.0"
}
