End-to-end deposit walk — project → quote → 50% prepayment → clickable pay-link → customer pays → receipt back → reconciled. For the ProMount by Vancomm (V2) entity.
This is the validation and reference runbook for the QBO ↔ Scoro bridge (spec 004-qbo-payments, Worker at scoro-qbo-bridge.vancomm.workers.dev). It walks one complete order from project creation through paid in full, for the 50%-deposit path: the customer pays a deposit upfront (Scoro prepayment invoice) and the balance on completion.
promount) entity. If the Scoro invoice list shows 4-digit invoice numbers (2914…) you’re on the wrong entity — switch via vancomm.scoro.com/?mode=switchCompany.
The deposit loop (steps 1–7: prepayment → QBO deposit invoice → clickable pay-link → customer pays → receipt back to Scoro) was walked live against the fixtures named here and confirmed end-to-end across both systems. Every mechanism listed is real and verified, not projected.
The final-invoice loop (steps 8–10) uses native connector mechanisms proven earlier the same session: a QBO payment auto-marked Scoro invoice 2346 paid via Receipts = To Scoro. A full order-fixture walk is pending.
| Step | Who does it | Status |
|---|---|---|
| Project / Company / Quote / Prepayment creation | Michael (Scoro UI) | ✓ Proven |
| Prepayment → QBO deposit invoice + clickable pay-link writeback | Worker (Path A) | ✓ Live (this walk) |
| Deposit payment → Scoro prepayment receipt | Worker (Path B, QBO webhook) | ✓ Live (this walk) |
| Final invoice → QBO sync → paid in full | Native connector (Path C) | ● Built + doc-verified; final-invoice live walk pending an order fixture |
| Mark delivered (Shipped/Picked Up) | Michael (Scoro UI) | ✓ Trivial |
Scoro fires a prepayment-created webhook. The Worker reads the prepayment (amount, percent), creates a QBO deposit invoice (Customer Deposit item → liability #15) for the advance amount, fetches the Intuit InvoiceLink, and writes <a href="…">Pay online</a> back into c_qbo_invoice_link on the Scoro prepayment.
✓ Live
When the customer pays the QBO deposit invoice, Intuit fires a payment webhook. The Worker posts a receipt against the matching Scoro prepayment (by prepayment_id, is_prepayment:1), taking it off Outstanding and reconciling the deposit.
✓ Live
Michael creates the final (balance) invoice in Scoro. The native Invoices = From Scoro connector syncs it to QBO. Customer pays; Receipts = To Scoro auto-marks the Scoro invoice paid in full. No Worker needed for this loop.
● Built + doc-verified; final-invoice live walk pending an order fixture
| What | Where / value |
|---|---|
| QBO Customer Deposits liability account | QBO chart of accounts — Id 15 (scripts/qbo-create-account.mjs) |
| QBO Customer Deposit service item → maps to #15 | QBO products/services — Id 4 (scripts/qbo-create-item.mjs) |
Custom field c_qbo_invoice_link, "Can add text in HTML format" = ON |
Scoro → Settings → Custom fields — field_id 27; scoped to invoices + prepayments. The HTML-format flag makes the stored <a href> render as a clickable link. |
| Connector Invoices = From Scoro | Scoro ↔ QBO connector settings — ON |
| Connector Receipts = To Scoro | Scoro ↔ QBO connector settings — ON (auto-marks Scoro invoices paid from QBO payments) |
| PDF templates: Quote 48, Prepayment 51, Invoice 49 | Scoro → Settings → PDF templates — carry [a]c_qbo_invoice_link[/a] in the Payment Instructions block |
Fixtures created for this walk. Reuse — don’t recreate:
| Object | Fixture ID | Notes |
|---|---|---|
| Project | 3031 | “QBO TEST Project” |
| Company / Person | 565 / 566 | “QBO Test Customer LLC” / “QBO Test Buyer” |
| Product | 4409 | ZTEST-PLT-6X6-14-G, $1.00, group V2_Raw Materials |
| Quote | 3290 (No. 5) | product 4409, 5% quote-level discount → Total $0.95 |
| Prepayment invoice | 128 (No. 2) | 50% deposit on quote 3290 → advance $0.50 |
Open Scoro in the ProMount by Vancomm entity. Create a new Project (fixture: #3031 “QBO TEST Project”) and link it to the company (fixture: #565 QBO Test Customer LLC). Ensure there’s a contact person (fixture: #566 QBO Test Buyer).
Make sure the product exists in the catalog (fixture: #4409 ZTEST-PLT-6X6-14-G, $1.00, group V2_Raw Materials, named per the product-naming convention).
From inside the project, click New Quote. Add product #4409 ($1.00). Apply the quote-level discount: triple-click the Discount field, type 5, Tab. Scoro auto-calculates the discount line on the PDF — it hides when 0%.
Result (fixture: Quote 3290, No. 5): Subtotal $1.00 — Discount (5%) −$0.05 — Total (USD) $0.95.
Quote 3290 PDF. The discount line is auto-rendered because the 5% field is non-zero. “This quote requires a 50% deposit at order confirmation.”
From the quote/order: Invoices → New prepayment invoice, set the advance to 50%. Scoro creates a prepayment for $0.50 (50% of $0.95, rounded to the configured precision).
Prepayments cannot be created via the API — they’re UI-only to mint. But they’re fully readable and writable via the REST API afterward (including invoices/prepayments/modify).
Fixture: Prepayment 128, No. 2.
This is the core of the bridge. In production the Scoro prepayment-created webhook triggers the Worker automatically. For this walk it was driven manually:
cd workers/scoro-qbo-bridge
npx esbuild src/index.ts --bundle --format=esm --platform=node \
--outfile=dist-node/index.mjs
doppler run -p vancomm -c dev_vancomm -- node test/drive.mjs \
POST /process/prepayment/128 \
'{"customerId":"9","billEmail":"worker-test@example.com"}'
What the Worker does (src/routes/process.ts → lib/qbo.ts + lib/scoro.ts):
invoices/prepayments/view/128 → reads sum=1.00, prepayment_percent=50.GET invoice/{id}?include=invoiceLink&minorversion=75 → pulls the Intuit InvoiceLink.invoices/prepayments/modify → writes <a href="…">Pay online</a> into c_qbo_invoice_link. The Worker echoes back prepayment_percent + custom_fields so the 50% advance isn’t reset to 100%.Verified response (2026-05-25):
{
"ok": true,
"scoroPrepaymentId": 128,
"fullSum": 1,
"prepaymentPercent": 50,
"depositAmount": 0.5,
"qboInvoiceId": "26",
"payLink": "https://connect.intuit.com/portal/app/CommerceNetwork/view/scs-v1-…",
"wroteAnchorTo": "c_qbo_invoice_link"
}
The Scoro prepayment record now shows the live pay-link in the c_qbo_invoice_link custom field:
Scoro prepayment 128 record after the Worker ran. The “Pay online” anchor is live in the c_qbo_invoice_link custom field — rendered as a clickable link because the HTML-format flag is ON.
And the same link renders on the customer-facing prepayment (deposit) PDF:
Prepayment 128 PDF. Math reconciles: “To be paid in advance (50%): 0.50” matches the Worker’s computed deposit amount. The Pay online link in PAYMENT INSTRUCTIONS is the live Intuit hosted invoice link.
In production the customer clicks Pay online and QBO records the payment; the Worker (on a QBO payment webhook) posts the receipt back to Scoro. For this walk both steps were driven manually:
# (a) Simulate the customer paying the QBO deposit invoice
doppler run -p vancomm -c dev_vancomm -- node test/drive.mjs \
POST /process/qbo-payment \
'{"customerId":"9","invoiceId":"26","amount":0.50}'
# → { "ok": true, "qboPaymentId": "27" }
# (b) Post the receipt against the Scoro prepayment
doppler run -p vancomm -c dev_vancomm -- node test/drive.mjs \
POST /process/receipt \
'{"prepaymentId":128,"contactId":565,"sum":0.50}'
# → { "ok": true, "reconciledPrepaymentId": 128 }
Receipts reference the prepayment by prepayment_id (is_prepayment:1, invoice_id:0). After this, prepayment 128 is reconciled (off Outstanding) — the deposit is received.
From the customer’s perspective, clicking Pay online opens the Intuit-hosted invoice page:
The Intuit-hosted pay-link page after QBO payment 27 was recorded. Mhondoro Capital Partners, LLC — amount $0.50 — Paid / $0.00 balance due. End-to-end confirmed live across both systems on 2026-05-25.
Move the order through the pipeline: In Process → Completed / Ready to Invoice. No QBO interaction at this stage — this is pure production work and internal pipeline management.
Status: built and doc-verified; final-invoice live walk pending an order fixture.
c_qbo_invoice_link field, so the regular-invoice pay-link applies here too.Invoices = From Scoro). Customer pays via the pay-link.Receipts = To Scoro auto-marks the Scoro invoice paid in full — no Worker needed for this loop. Then set the order to Shipped/Picked Up (pipeline stage 10) = delivered.The native connector mechanism is confirmed: a $1 QBO payment auto-marked Scoro invoice 2346 paid via Receipts = To Scoro earlier the same session. Path C requires no Worker code for the regular-invoice loop.
Before the Worker handles live traffic, three things must be wired in production:
prepayment_created event in Scoro webhooks, pointing at the deployed Worker’s /webhook/scoro endpoint. Until this is wired, Path A requires manual test/drive.mjs invocations./webhook/qbo endpoint in the Intuit Developer portal. Set the INTUIT_WEBHOOK_VERIFIER_TOKEN secret in Cloudflare KV or Doppler (vancomm project, dev_vancomm config). Until this is wired, Path B requires manual test/drive.mjs POST /process/receipt.qbo-token.ts manages rotation from KV). Run: tailscale funnel 8742 && doppler run -- node scripts/qbo-oauth.mjs. Calendar the 100-day re-run.wrangler deploy (gated on approval)
workers/scoro-qbo-bridge/wrangler.toml.Deposit loop proven live 2026-05-26
Prepayment 128 → QBO deposit invoice 26 → $0.50 paid → receipt back to Scoro → reconciled. End-to-end. Both systems.
Path C (final invoice via native connector) is built and verified against invoice 2346. The full order walk will confirm it against a real order fixture.
Need the printable version?
The print page has a condensed one-sheet of the walk: the step sequence, automation paths, and production checklist — designed to fit on letter paper.
Open print version →