Holded Stripe integration
Stripe payments booked in Holded with no Excel and no manual reconciliation.
Implementation time · 4-7 días laborables
The problem
Stripe is excellent at collecting payments: payment links, recurring billing, card management, everything you need. But it leaves Spanish accounting invoicing completely orphaned. To reconcile 200 monthly payments with your Holded, someone ends up downloading Stripe's monthly CSV, opening it in Excel, looking up each customer and creating invoices by hand. Once you pass 50 payments a month, this is 5 to 10 hours of admin every month just moving data around. Stripe Invoicing exists, but its numbering does not fit the AEAT, it lacks the Spanish tax models (303, 390, 349) and it handles intra-community VAT poorly. Holded does handle all of this, but by default it does not listen to Stripe.
ProposalThe solution
Every Stripe payment (one-off, subscription, payment link, payment element) generates the matching invoice in Holded with the correct customer, VAT and series. Refunds trigger credit notes. Stripe fees are booked as an expense in their matching account. Payments in other currencies are recorded with their EUR equivalent at Stripe's own exchange rate. Idempotency guaranteed with Stripe's event ID: infinite retries never duplicate anything.
What we automate
- PaymentIntent succeeded to Holded invoice with correct customer, VAT and series
- Stripe Subscription renewal to recurring invoice with the recurring series
- Stripe Checkout or Payment Link to invoice after succeeded
- Stripe refund (full or partial) to Holded credit note
- Stripe fee to an expense entry in the accounting account you define
- Multi-currency with EUR equivalent at Stripe's own rate
- Failed payments to a Holded notification for dunning management
- Customer Portal: plan changes reflected in the next recurring invoice
- Stripe Tax IDs to tax ID or VIES in Holded with intra-community validation
Real use cases
These are the profiles that most ask us for the Holded ↔ Stripe integration and what they get in the end.
B2B SaaS with Stripe subscriptions (200 active customers)
Before: Every monthly renewal required admin to create the invoice by hand. 8 hours a week.
After: Automatic renewals with the correct recurring series. Admin is left only with failure dunning.
DTC ecommerce collecting with Stripe plus Klarna
Before: 200 payments a month, partial refunds for returns, discount codes.
After: Invoice issued in seconds after succeeded. Partial refunds become exact credit notes. Zero leakage.
Consultancy with international payments in USD
Before: USD payments were invoiced at the bank's daily rate, creating mismatches with the actual collection.
After: Exchange rate locked to Stripe's own rate. Bank and Holded match to the cent.
What changes exactly
Without the integration
- Stripe's monthly CSV opened in Excel and cleaned by hand
- 5 to 10 hours a month generating invoices for Stripe payments
- Partial refunds badly reflected or ignored
- Stripe fees never booked as an expense
- Multi-currency with EUR/USD gaps
With the integration
- Stripe webhook to Holded invoice in seconds
- Zero admin for successful payments, only failure dunning
- Automatic partial credit notes with the exact amount
- Stripe fees as an accounting expense entry
- Multi-currency with Stripe's own EUR equivalent
How we build it
A signed Stripe webhook endpoint (HMAC verification with the secret) that filters only the relevant events: payment_intent.succeeded, charge.refunded, invoice.payment_succeeded, customer.subscription.updated. A persistent BullMQ queue, an idempotent worker with dedupe by Stripe event.id, and calls to the Holded REST API with backoff. All the mapping logic (which Stripe Product to which Holded item, which series by currency or payment type) lives in versioned config. If Holded is down, we retry for 24 hours; if it still fails after that, we alert by email or Slack.
Frequently asked questions
What about payments in USD or other currencies?
We record the EUR equivalent using Stripe's own exchange rate (the one that applies to the payout). That removes any gap between what Stripe pays into your bank and what shows in Holded.
Does it work with Stripe Subscriptions and Stripe Billing?
Yes. Each renewal triggers a Holded recurring invoice with the series you define. Plan changes (upgrade or downgrade) generate invoices with proration identical to Stripe's own calculation.
How are chargebacks handled?
When Stripe notifies a dispute, we record it as a pending credit note. If the merchant wins, the credit note is voided; if the customer wins, it is closed as final. You keep full tax traceability at all times.
Is Stripe Connect (marketplace) supported?
Yes. For marketplaces using Connect, we generate the buyer's invoice and separate the platform fee as your own income. Transfers to partners are booked as accounting expenses.
Intra-community tax ID in Stripe?
Yes. Stripe lets you store Tax IDs on the Customer. We read them and validate against VIES at the time of payment. If it is a valid intra-community B2B, VAT is 0%; if not, the local rate of the country applies.
And failed payments or dunning?
The failed_payment events are reflected in Holded as pending invoices. We can also integrate with your CRM (HubSpot, Pipedrive, and so on) so that sales sees the churn risk.
Related integrations
QuickBooks + Stripe
Every Stripe charge, refund and payout lands in QuickBooks on its own, with fees split out and the bank reconciled.
See integrationPaymentsXero + Stripe
Stripe payments, refunds and payouts pushed to Xero and grouped so the bank matches.
See integrationPaymentsNetSuite + Stripe
Stripe payments, refunds, payouts and subscriptions reconciled in NetSuite, with revenue schedules and automatic bank matching.
See integrationShall we talk about your Stripe integration?
A 30-minute call, no strings. You leave with scope and a price.