- Add GET /portal/config returning stripePublishableKey from env
- Rename createdAt→date in invoice response to match BillingPayments interface
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Install @stripe/stripe-js and @stripe/react-stripe-js
- Replace BillingPayments mock delay with real Stripe Elements:
- Fetch publishableKey from GET /api/portal/config
- Lazy load Stripe via loadStripe()
- Wrap payment modal in <Elements> with PaymentElement
- Use stripe.confirmPayment() with clientSecret from pay/pay-multiple endpoints
- Support multi-invoice selection and single invoice payment
- Add "Save card for future payments" checkbox (setup_future_usage)
- Add payment method management: list saved cards, delete via DELETE endpoint
- Proper error handling for payment failures
- Autopay toggle (UI-only, Phase 2 backend pending)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Portal routes (client-facing):
- POST /api/portal/invoices/:id/pay - create PaymentIntent for single invoice
- POST /api/portal/invoices/pay-multiple - create PaymentIntent for multiple invoices
- GET /api/portal/payment-methods - list saved payment methods
- POST /api/portal/payment-methods - create SetupIntent for saving new card
- DELETE /api/portal/payment-methods/:id - detach payment method
- GET /api/portal/config - return Stripe publishable key
Admin routes:
- POST /api/invoices/:id/refund - manager-only refund endpoint
Validation:
- Cannot pay draft, void, or already-paid invoices
- Multi-invoice: all must belong to same client and be pending
- Refund requires invoice to be paid with stripePaymentIntentId
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Added telnyx npm package
- Created sms.ts with SmsProvider interface
- Implemented TelnyxProvider with sendSms() and validateWebhookSignature()
- Added createSmsProvider() factory function
- Added smsSend() convenience function that skips when SMS_ENABLED=false
- Provider abstraction allows future Twilio or other providers
- E.164 phone validation on send
- Webhook signature verification using HMAC-SHA256
Co-Authored-By: Paperclip <noreply@paperclip.ing>