Guide

Build the Change‑Order Autopilot (Slack + Notion + PandaDoc + Stripe) — Zapier/Make Guide

A paste‑ready build guide for solo operators: capture requests in one place, auto‑classify scope, price from a SKU table, generate a PandaDoc change order, and hard‑gate work until Stripe confirms payment. Works in Zapier or Make with Slack, Notion, PandaDoc, and Stripe wired end‑to‑end.

Use this guide to ship the exact change‑order automation from the episode. It captures every client request, classifies scope, prices from a SKU table, generates a PandaDoc change order, and blocks delivery until both signature and payment clear. Written for solo operators who need a copy‑ready, numbers‑first build without hiring a PM.

1) System architecture at a glance

  • Single intake: All client requests enter one gate (Slack channel or form) and land in Notion Requests.
  • AI classification: Compare the request to the signed SOW; return inscope or outof_scope plus a suggested SKU.
  • Price lookup: Pull price/terms from Notion Change Order SKUs.
  • One‑click approval in Slack: Approve/Reject with optional price override.
  • Parallel generation: Create PandaDoc from template and a Stripe Payment Link; attach link to the doc email.
  • Hard gate: Create a task marked “Blocked — Awaiting CO.” Work unblocks only after two events: PandaDoc completed AND Stripe payment succeeded.
  • Logging & reporting: Update a Notion Change Orders record; roll up monthly revenue, AOV, and top SKUs.

Golden rule: No signature + money = no work. The system enforces it so you don’t have to.

2) Notion data layer (schemas you can paste)

Create three databases exactly once. Keep property names consistent with your automations.

A) Requests (intake queue)

  • Name (Title)
  • Client (Relation → Clients) — optional but recommended
  • Request text (Rich text)
  • Scope status (Select: In Scope, Out of Scope, Unclear)
  • Suggested SKU (Relation → Change Order SKUs)
  • Quoted price (Number, currency)
  • Change Order (Relation → Change Orders)
  • Created time (Created time)

B) Change Order SKUs (your rules/pricing table)

  • SKU name (Title) — e.g., “Analytics dashboard (up to 6 KPIs)”
  • Price (Number, currency)
  • Delivery window (Number) — business days after payment
  • Terms (Rich text) — any additions beyond master agreement
  • Active? (Checkbox)

C) Change Orders (contract + payment log)

  • CO ID (Title) — e.g., “CO‑2026‑03‑017”
  • Client (Relation → Clients)
  • Source request (Relation → Requests)
  • Scope delta (Rich text) — human‑readable description
  • Price (Number, currency)
  • Delivery window (Number)
  • PandaDoc doc ID (Text)
  • Stripe link ID (Text)
  • Signature status (Select: Pending, Completed, Declined)
  • Payment status (Select: Pending, Succeeded, Refunded, Failed)
  • Gate status (Formula) — unblocks work only when both are complete

Recommended Gate status formula (Notion):
```
if(
and(
prop("Signature status") = "Completed",
prop("Payment status") = "Succeeded"
),
"Ready",
"Blocked — Awaiting CO"
)
```
Performance tips

  • Use filtered views (e.g., Created time is within past 90 days) for large Requests DBs.
  • Keep Relations/Rollups only where reporting requires them to minimize view load.
  • Reserve Rich text for human‑readable summaries; store automation keys in plain Text.

3) Intake + AI classification (copy-ready prompts)

Intake options

  • Slack: Route all client asks into #client-requests (clients in shared channels or CSEs) and forward DMs via a slash command or Workflow Builder.
  • Form: Use a short form (e.g., Fillout/Typeform) that writes to Notion Requests for clients who don’t live in Slack.

AI step (Zapier AI or Make OpenAI/ChatGPT module)

  • Inputs: SOW text, request text, list of SKU names + price anchors.
  • System prompt (paste as System):

```
You are a scope classifier for a service business. Compare the signed Statement of Work (SOW) to a new client request. Return JSON with:

  • scopestatus: one of ["inscope","outofscope","unclear"]
  • suggestedsku: EXACT match from skulist or null
  • rationale: one sentence explaining the decision

Bias toward "outofscope" when the request adds deliverables, increases complexity, or changes timelines.
```

  • User content template:

```
SOW:
{{sow_text}}
---
Request:
{{request_text}}
---
sku_list:
{{sku_names}}
```

  • Expected model output:

```
{
"scopestatus": "outof_scope",
"suggested_sku": "Analytics dashboard (up to 6 KPIs)",
"rationale": "Dashboards are not included in SOW section 3.2"
}
```
Routing rules

  • in_scope → create normal task; notify you.
  • outofscope → lookup SKU in Notion; prefill price; continue to Slack approval.
  • unclear → set Scope status=Unclear; drop a Slack DM to review manually.

Safeguards

  • If confidence is low or no SKU matches, default to Unclear (no auto‑pricing).

4) Slack approval UX (buttons + optional modal)

Two practical approaches — pick one.

A) Workflow Builder (no custom app)

  • Post a message to you with two buttons: Approve, Reject.
  • On Approve, open a form step to edit Price and Delivery window.
  • Branch:
  • Approve → continue automation with overrides.
  • Reject → set a Follow‑up task in Notion and stop.

B) Lightweight custom app (for best UX and price edit modal)

  1. Send an interactive message (Block Kit) to your DM:

```json
{
"blocks": [
{"type":"section","text":{"type":"mrkdwn","text":"Change order suggested: {{skuname}}{{price}}\n> {{scopedelta}}"}},
{"type":"actions","elements":[
{"type":"button","text":{"type":"plaintext","text":"Approve"},"style":"primary","actionid":"coapprove","value":"{{coid}}"},
{"type":"button","text":{"type":"plaintext","text":"Reject"},"style":"danger","actionid":"coreject","value":"{{coid}}"}
]}
]
}
```

  1. On Approve, open a modal (views.open) to edit price:

```json
{
"type": "modal",
"callbackid": "coprice_submit",
"title": {"type":"plain_text","text":"Confirm Change Order"},
"submit": {"type":"plain_text","text":"Continue"},
"privatemetadata": "{{coid}}",
"blocks": [
{"type":"input","blockid":"price","label":{"type":"plaintext","text":"Price (USD)"},
"element":{"type":"plaintextinput","actionid":"priceinput","initial_value":"{{price}}"}},
{"type":"input","blockid":"window","label":{"type":"plaintext","text":"Delivery window (business days)"},
"element":{"type":"plaintextinput","actionid":"windowinput","initial_value":"{{window}}"}}
]
}
```

  1. Persist overrides to Notion and continue.

Notes

  • Slack trigger_id expires quickly; open the modal immediately on Approve.
  • Keep the approval surface to one DM thread per request to reduce context switching.

5) PandaDoc template + generation (fields you need)

Template requirements (make once, reuse forever)

  • Merge variables: clientname, scopedelta, price, deliverywindowdays, coid, masteragreementdate, clauseref.
  • Subject: Change Order {{coid}} — {{clientname}}.
  • Body must include:
  • A short scope delta paragraph.
  • Price in USD and taxes note.
  • Delivery window (“within {{deliverywindowdays}} business days of payment clearance”).
  • Clause reference that ties to master agreement.
  • Signature block.

Clause reference language (run by counsel once):
> This Change Order modifies the Service Agreement dated [{{masteragreementdate}}] between [{{client_name}}] and [Provider]. All other terms remain in effect.

Automation action

  • Use “Create document from template.” Map each merge variable from Notion fields.
  • Store the returned PandaDoc document ID in Notion Change Orders → PandaDoc doc ID.

Plan note

  • If you’re not on PandaDoc Enterprise (native webhooks), rely on Zapier/Make’s “Document Completed” trigger for the signature signal. Works reliably for solo ops.

6) Stripe Payment Link + metadata (payment gate)

Use Payment Links for fixed SKUs; if you need ad‑hoc pricing, create a one‑off Price object or fall back to an Invoice.

Recommended metadata keys (set on PaymentIntent via paymentintentdata.metadata)

  • co_id — your Change Orders CO ID
  • pandadocdocid — for correlation
  • client_id — your Client record key

Option A — Pre‑created Prices per SKU

  • Keep one Price per active SKU.
  • Create a Payment Link referencing that Price and attach metadata.

Example (HTTP request you can run from Make/Code step):
```
POST https://api.stripe.com/v1/payment_links
Authorization: Bearer {{STRIPESECRETKEY}}
Content-Type: application/x-www-form-urlencoded

lineitems[0][price]={{priceid}}&
line_items[0][quantity]=1&
paymentintentdata[metadata][coid]={{coid}}&
paymentintentdata[metadata][pandadocdocid]={{pandadocdocid}}&
paymentintentdata[metadata][clientid]={{clientid}}&
after_completion[type]=redirect&
aftercompletion[redirect][url]=https://{{yourdomain}}/payments/thanks?co={{co_id}}
```
Store the returned id (e.g., plink_...) in Notion Change Orders → Stripe link ID.

Option B — Variable pricing

  • Create a one‑off Price (standard) with the desired unit amount, then create the Payment Link using that Price.
  • If you invoice instead (Stripe Invoice), store the invoice.id and listen for invoice.paid.

Taxes & receipts

  • Toggle Stripe Tax or attach your static tax rates to the Price. Stripe emails a receipt automatically after payment succeeds.

7) Orchestration + task gating (Zapier and Make maps)

Two equivalent builds — choose your platform.

Zapier path (human‑readable)

  1. Trigger: New Request in Notion (or Slack message/form submission → create Request).
  2. AI Classifier: Zapier AI step → JSON with scopestatus, suggestedsku.
  3. Filter/Paths:
  • Path A In Scope → create normal task; Slack FYI; STOP.
  • Path B Out of Scope → continue.
  1. Notion: Lookup SKU → get Price + Delivery window.
  2. Slack: Send Approve/Reject DM; on Approve open form/modal for overrides.
  3. Paths: If Approved → continue; If Rejected → write note in Notion; STOP.
  4. Parallel actions (use two Zaps or one Zap with multiple actions):
  • Create PandaDoc from template; save document_id.
  • Create Stripe Payment Link; save plinkid with metadata including documentid.
  1. Email: Send PandaDoc doc to client; include the Payment Link and the sentence: “Work begins when signature and payment clear.”
  2. Task tool: Create task with status “Blocked — Awaiting CO.”
  3. Listener Zaps (two separate Zaps):
  • On PandaDoc Completed → update Change Orders Signature status=Completed.
  • On Stripe Payment Succeeded (webhook or Stripe app) → update Payment status=Succeeded.
  1. Unblocker Zap: When both statuses are complete → set Gate status=Ready; update task (Asana dependency cleared / Jira flag off / Trello unblocked) and send Slack “All clear.”

Make scenario (visual router)

  • Scenario A (main): Intake → AI classifier → Router (Approved/Rejected). Approved branch splits into two parallel modules: PandaDoc (Create from template) and HTTP (Stripe Payment Link). Join with an aggregator; then email client and create Blocked task.
  • Scenario B: Webhook — PandaDoc completed → update Signature status.
  • Scenario C: Webhook — Stripe payment succeeded → update Payment status.
  • Scenario D: Poll/trigger — When both complete → unblock task + Slack notify + log revenue.

Task gating patterns

  • Asana: Create task, then add a dependency “Blocked by: Change Order {{co_id}}.” Clear this when Gate status flips to Ready.
  • Jira: Apply a red flag or move to a custom “Blocked — Awaiting CO” status; remove the flag/status on Ready.
  • Trello: Use a dependency/blocked Power‑Up to mark/unmark blocks automatically.

8) Exceptions, testing, and maintenance

Edge cases you must handle

  • Signed but unpaid (common): After 48 hours, auto‑email a payment reminder and ping Slack. Pause work.
  • Paid but unsigned (rare): Email signature reminder; pause work; flag for manual review.
  • Negotiation: Slack Reject path writes a follow‑up note in Notion and assigns you a call task.
  • Cancellation/refund: If Payment refunded, set Payment status=Refunded, revert Gate status to Blocked, and notify.

Testing & rollout (1–2 hours)

  • Stripe in Test mode: Verify Payment Link creation and payment_intent.succeeded webhook with your metadata.
  • PandaDoc: Send to a secondary email; verify Completed trigger fires and the correct Notion record updates.
  • Join logic: Flip only one status at a time to confirm the task stays Blocked until both are true.
  • Failure injection: Reject in Slack; ensure the automation fully stops and leaves an audit note.

Audit & reporting

  • Notion rollups on Change Orders: monthly revenue, average order value, top 5 SKUs.
  • Slack digest (weekly): “Change‑order revenue last 7 days: $X across Y orders. Top SKU: Z.”
  • KPIs to watch: Change‑order revenue/month, time‑to‑approval (median), unpaid aging (48h+), automation success rate (target ≥ 93%).

Copy blocks you can reuse

  • Email line: “Work begins when signature and payment clear.”
  • CO description scaffold: “Add [deliverable] to [project/system] including [scope notes]. Will be delivered within [N] business days of payment clearance.”

Security & legal

  • Store only lookup metadata in Stripe (IDs, not PII). Limit who can trigger Approve/Reject.
  • Include a clause reference to your master agreement in every change order and have an attorney review your template once.

Time/cost expectations (solo operator, v1)

  • Notion schemas: ~20–30 minutes
  • Slack approval + AI step: ~30–45 minutes
  • PandaDoc template: ~30 minutes (one‑time)
  • Stripe link wiring: ~20 minutes
  • End‑to‑end tests: ~30 minutes
  • Typical classification latency: ~12 seconds (model + network)

Result: A durable gate that turns “quick favors” into paid, scheduled work.