Runbook — Manual payments (ADR-0132 Phase 1 / ADR-0134 D3)
How staff fulfil a paid-plan upgrade while self-serve checkout is deferred
(ADR-0131). The customer-facing path is Contact us → sales@puccha.ai; this
is the staff side.
Who: superadmin only. Where: /admin/payments (Staff console → Payments).
Audit: every activation writes a plan_changed lifecycle event; the request
keeps external_ref + timestamps.
Happy path
Section titled “Happy path”- A request appears. When a customer clicks Contact us on their billing
page, a
payment_requestis recorded (status = pending) and an email lands insales@puccha.ai. It shows in/admin/payments, pending on top. Target SLA: respond within 1 business day. An Enterprise click arrives as an unquoted request (amount to quote, ADR-0191): agree the figure with the customer, then Quote on the row to set it — Mark paid is unavailable until then. Re-quote also discounts a list-price request from any tier. For deals with no customer click at all, open one yourself: New request on/admin/payments(or New request on the tenant’s hub page) — the amount prefills at list price and is editable; put the quote reference in the note (it lands in the tenant’s audit log). One open request per tenant (ADR-0189). - Verify the request: tenant, plan, cycle, and amount (฿) shown in the row. Confirm it matches what the customer asked for.
- Collect payment off-platform. Send the customer payment instructions on any channel — PromptPay QR, bank transfer details, or a hosted link. Use the amount shown.
- On confirmed receipt, capture the proof reference (bank slip no. /
transfer id) for the record, then click Mark paid on that row.
- This calls
applyPlanChange→ sets the tenant’s plan + emitsplan_changed. - The row flips to activated; the customer is now on the new plan.
- This calls
- Tell the customer it’s active (reply to the original thread).
Edge cases
Section titled “Edge cases”- Wrong / partial amount. Do not Mark paid. Reply to the customer for the
balance; the request stays
pending. (No partial activation.) - Customer paid but the plan is wrong. Mark paid activates the plan recorded on the request. If the request itself is wrong, do not Mark paid — Cancel the wrong row and open a fresh one with the right plan (New request).
- Mistaken activation (activated the wrong tenant/plan). Click Reverse
on the activated row (ADR-0138). It rolls the tenant back to the plan it was on
before activation (
prior_plan), emits aplan_changedevent (so it’s audited), and flips the request toreversed. It does not refund — settle any money on the original channel. Caveat: requests activated before ADR-0138 shipped have noprior_plan, so no Reverse button appears — for those, reverse manually: confirm the prior plan from the tenant’splan_changedevents at/admin/tenants/<id>/health, then have an engineer run the correctiveUPDATE tenants SET plan=… WHERE id=…and record it in the ops log. - Duplicate requests for the same tenant/plan: activate one, Cancel the rest; don’t Mark paid twice — activation is idempotent, but two activated rows muddy the queue.
- Stale requests (customer never paid): Cancel them. An open request is also the floor for comps (a comp can’t land below it, ADR-0161 / #544), so a stale row will block staff from comping the tenant to a lower tier until it is cancelled. Cancelling never changes entitlement.
- Refunds / disputes / chargebacks: manual today — coordinate the refund on the original payment channel and downgrade the plan as in mistaken activation. A proper refund/credit system lands with a live processor (own ADR).
- Amounts come from
PLAN_META.thb(+ seat add-ons); annual = 12 months at the 20%-off rate (ADR-0038). For Enterprise / negotiated deals enter the agreed figure on the New-request form, and set the tenant’s negotiated MRR viaquotasJson.mrrThbso the FinOps margin view (ADR-0130,/admin/finops) reflects reality. - Idempotent: Mark paid on an already-activated request is a safe no-op.
- Future channels (PromptPay auto-verify, Stripe) plug in behind the same
payment_request+applyPlanChangeseam (ADR-0132) — this runbook’s “collect- Mark paid” steps become automatic per channel; the edge cases stay relevant.