FrancodesystemsFran<code>systems
CRMCustom integration

Holded HubSpot integration

HubSpot and Holded sharing customers, opportunities and invoicing in real time.

HoldedHolded
HubSpot

Implementation time · 7-12 días laborables

Diagnosis

The problem

Your sales reps live in HubSpot. Your back office lives in Holded. And the data does not talk to each other: each side has its own version of reality, duplicates pile up, and reps never know whether an invoice is paid without opening a Slack channel to ask accounting. Every won deal turns into 15-30 minutes of manual admin work: copy the contact, validate the tax ID, create the estimate, send the invoice, register the payment. In teams with 50 deals/month that is 25 monthly hours the admin team spends on copy-paste instead of value-adding tasks. Commercial connectors like Zapier or the HubSpot marketplace apps solve the trivial case but generate duplicates, do not handle intra-community tax IDs well and fall short in scenarios with complex line items.

Proposal

The solution

Contacts and companies created in HubSpot are automatically reflected in Holded with their validated tax ID and their commercial category. Won deals trigger an estimate or invoice in Holded based on the configured pipeline stage. The payment status (issued, paid, overdue) flows back to HubSpot as deal and contact properties, so sales reps see the financial status without leaving the CRM. The product catalog lives as the single source of truth on one of the two sides and is replicated automatically.

Scope

What we automate

  • HubSpot contact/company to Holded contact with validated tax ID (VIES if intra-community)
  • Deal in stage X to Holded estimate; deal Closed Won to issued invoice
  • HubSpot line items (quantity, price, discount) to Holded invoice lines with correct VAT
  • Holded payment status to deal and contact properties in HubSpot
  • Holded products to HubSpot catalog (single source on one of the two sides)
  • Sales rep assigned to the deal to salesperson on the Holded invoice for commissions
  • Support tickets in HubSpot Service Hub to tasks or notes in Holded
  • HubSpot forms that generate deals to pre-created Holded contacts
Who uses it

Real use cases

These are the profiles that most ask us for the HoldedHubSpot integration and what they get in the end.

Case 01

B2B agency with 80 deals/month

Before: Admin spent 30 h/month generating estimates and invoices from deals closed in HubSpot.

After: Deal Closed Won to invoice in 5 seconds. Admin moves on to collections and reconciliation, not copy-paste.

Case 02

SaaS with per-seat pricing

Before: HubSpot line items with variable quantities (X seats times Y price) did not map well to Holded.

After: Each deal line item goes as an invoice line with correct quantity and price. Upsells generate corrective invoices.

Case 03

Team with HubSpot Service Hub

Before: Billable support tickets (extra implementation hours) never reached Holded.

After: Ticket closed with a 'billable' tag to a line on the customer's recurring monthly invoice.

Before / After

What changes exactly

Without the integration

  • Sales reps with no visibility into payment status
  • Admin loses 25+ h/month copying deals to Holded
  • Duplicate contacts between HubSpot and Holded
  • Billable tickets that never reach the ERP
  • Intra-community tax ID checked by hand on every deal

With the integration

  • Payment status visible on the sales rep's deal
  • Deal Closed Won to issued invoice in seconds
  • Matching by email + tax ID: zero duplicates
  • Billable support propagated automatically
  • VIES validated before generating anything in Holded
Architecture

How we build it

HubSpot webhooks (contact.creation, deal.propertyChange) enter a queue with persistence. The worker matches by email + tax ID before creating anything in Holded, so we never duplicate contacts. The Holded REST API receives estimates or invoices depending on the configured deal stage, and the result flows back to HubSpot as a custom property of enum type. Everything idempotent with the HubSpot event ID. If HubSpot sends the same event twice (which happens), we do not create duplicates.

flow.ts
webhook hubspot.event
queue.enqueue(jobId)
worker.handle() // idempotent
holded.api.call() // retries with backoff
log.emit({ status: 'ok' })
FAQ

Frequently asked questions

Does it create duplicates if the contact already exists in Holded?

No. Before creating anything we match by primary email and tax ID. If the contact already exists, we update it instead of duplicating. If there is a conflict (same email, different tax ID), we flag it for human review instead of guessing.

At what point in the pipeline does it generate an invoice?

You configure it. The usual setup is: deal in the 'Proposal sent' stage to an estimate in Holded; deal in 'Closed Won' to an issued invoice. But we can trigger whatever you want based on stage, custom property, or a manual trigger.

Does it work with HubSpot Operations Hub?

Yes. If you already have workflows in Operations Hub, we can connect as a webhook target instead of a native listener. You keep control of the logic in HubSpot and we just execute against Holded.

Does it support line items with per-line discounts?

Yes. Each deal line item goes as an invoice line in Holded with its unit price, quantity and applied discount. VAT is calculated on the already discounted base.

Does the payment status flow back to HubSpot?

Yes. We create custom properties on the deal and the contact (Invoice status, Payment date, Overdue amount) that update in real time from Holded. Sales reps see it on the deal panel.

How long does it take to be up and running?

Between 7 and 12 days for a standard integration. Catalog mapping, custom properties and workflows can add 3-5 days depending on complexity.

Shall we talk about your HubSpot integration?

A 30-minute call, no strings. You leave with scope and a price.