WorkestraDocs
ModulesFinance

Payments

Accept card payments on invoices with Stripe. Multi-provider architecture — Mollie and others slot in without workflow changes.

Let your customers pay invoices online with a credit or debit card. Workestra's payments pipeline is multi-provider from day one — Stripe is ready today, Mollie is on the way, and adding other gateways won't change how you send invoices or how they settle.

Payments is an opt-in capability. Workspaces without a configured provider still send invoices normally — the "Pay link" button and email CTA just don't appear.

What you get

  • Hosted checkout. Customers click a pay link and land on the provider's secure checkout page. You never handle card data.
  • Automatic invoice settlement. When a payment succeeds, the invoice flips to Paid (or Partial if the amount was less than the balance) within a second or two of the provider's webhook.
  • Pay link anywhere. Every sent invoice exposes a "Pay link" button. Share it in an email, a chat, or include it automatically in the sent-invoice email.
  • Ledger of every payment. Each successful charge is recorded on the invoice with the provider reference, amount, and timestamp.
  • Encrypted credentials. Stripe and Mollie API keys are encrypted at rest with AES-256-GCM before they're stored. They're never displayed again after you save them — only masked.
  • Idempotent webhooks + DLQ. Duplicate webhook events can't double-credit an invoice. Permanently failing events fall through to a dead-letter queue and are retried automatically.
  • Audit-logged. Saving or rotating Stripe keys is recorded in the workspace audit log (key hash only — never the secret itself).
  • Refund-ready. Full and partial refunds work via API today; a refund button on the invoice detail page lands in a follow-up release.

Providers

ProviderStatusCoverage
Stripe✅ Available nowGlobal — all card types Stripe supports
Mollie🚧 ScaffoldedEU-first; implementation pending
OthersExtensibleAdyen, PayPal, etc. can be added without changing routes or UI

Connecting Stripe

Setup takes ~5 minutes.

1. Get your Stripe keys

From the Stripe dashboard:

  • Copy the Secret key (sk_test_… in test mode, sk_live_… in production)
  • Copy the Publishable key (pk_test_… / pk_live_…)

2. Add the webhook endpoint

In Stripe Developers → Webhooks → Add endpoint:

  • URL: https://<your-workspace-domain>/api/finance/payments/stripe/webhook
  • Events to listen for:
    • checkout.session.completed
    • checkout.session.async_payment_succeeded
    • checkout.session.async_payment_failed
  • After creating, reveal the Signing secret (whsec_…)

3. Save the keys in Workestra

  1. Navigate to Finance → Settings → Payments
  2. Paste all three keys (secret, publishable, webhook)
  3. Pick Test or Live mode
  4. Toggle Offer card payment on invoices on
  5. Click Save Stripe

The workspace is now ready to accept card payments.

Use Test mode to verify the end-to-end flow with Stripe's test card 4242 4242 4242 4242. Switch to Live when you're ready for real charges.

Once Stripe is connected, every Sent or Overdue invoice shows a Pay link button in the action bar.

Click it to:

  1. Generate the checkout URL
  2. Copy it to the clipboard for pasting into a message
  3. Open it in a new tab to verify the customer experience

The same URL is automatically included in the invoice email when you click Send.

What the customer sees

The payer clicks the link and lands on Stripe's hosted checkout page. They pay with a card. On success they're redirected to a branded confirmation page (/pay/success). If they cancel, they land on /pay/cancel. Neither page leaks workspace data.

Settlement flow

The moment Stripe confirms a payment, the webhook posts to your workspace:

Stripe → /api/finance/payments/stripe/webhook

       verifies signature

       records invoice_payments row

       recomputes invoice paid_amount

       flips invoice to Paid or Partial

Webhook events are idempotent — Stripe can redeliver the same event and the invoice won't be double-credited. Every successful payment leaves an auditable record on the invoice (provider reference + event ID + amount).

Statuses

Payment statusMeaning
PendingCustomer started checkout, no charge yet
SucceededCard was charged; invoice updated
FailedCharge declined or error during checkout
RefundedFull refund issued
Partially refundedPartial refund issued
CancelledCustomer abandoned the checkout

Sending invoices with pay CTA

When Stripe is active:

  1. Open an invoice
  2. Click Send
  3. The email goes out with:
    • The full invoice as a PDF attachment
    • A prominent Pay online button
    • The amount and due date up front

When Stripe is not active, the same email goes out with the PDF but without the pay button — no action required to disable anything.

Refunds

Full and partial refunds are supported at the API + service-layer level today. A first-class refund button on the invoice detail page is on the roadmap and ships in a follow-up release. In the meantime:

  1. Trigger the refund directly from the Stripe dashboard (or via the AI assistant — see AI Tools).
  2. Workestra's webhook records the refund automatically as a refunded or partially_refunded entry on the invoice's payment ledger.
  3. The invoice's outstanding balance is recalculated; status flips back to Sent / Partial as needed.

Troubleshooting

Pay button missing on a sent invoice. Confirm the payment provider is toggled Active at /finance/settings?tab=payments. Inactive providers don't generate pay links.

Webhook signature failures. The signing secret in Workestra must match the one from Stripe's webhook endpoint configuration. If you regenerate it in Stripe, update Workestra immediately or webhooks will be rejected.

Invoice didn't flip to Paid. Check the Stripe dashboard → Developers → Events for the checkout.session.completed event. If it shows an HTTP error on delivery, the webhook URL or signing secret is wrong. Stripe retries automatically for ~3 days, so fixing the config usually recovers the settlement.

Removing a provider

To disconnect Stripe:

  1. Go to Finance → Settings → Payments
  2. Click Disconnect Stripe
  3. Confirm

The invoice Pay link button disappears immediately. Historical invoice_payments records stay intact — disconnecting the provider doesn't delete the payment ledger.


Next steps