HubfiscalStoreShopify
Description
Section titled “Description”Receives a raw Shopify order payload (from a webhook or previous node) and stores it in the Hub Fiscal centralized MySQL/MariaDB database as pending. Designed to be placed at the beginning of a fiscal workflow, before invoicing, to queue the order and ensure no order is ever lost even if the fiscal provider step fails later.
Key features:
- Upsert: If the order already has a record (same
entity_id+entity_source+type), it updates only safe fields (status stayscompleted/failedonce set). Prevents duplicates on Shopify webhook retries. - Auto-detection: Extracts country from
billing_address.country_codeand auto-selects the fiscal provider (PT/AO/MZ → billpt, ES/DE → fiskaly). - NIF resolution: Reads the customer NIF/VAT from Shopify
note_attributes(configurable key). - Atomic transaction: Inserts into
documents,fiscal_statusandlogsin one transaction.
Configuration
Section titled “Configuration”| Field | Type | Required | Description |
|---|---|---|---|
| credentials_id | credentials | Yes | Hub Fiscal MySQL/MariaDB credential (sqlQuery type) |
| country_iso | text | No | Country ISO code. Defaults to billing_address.country_code |
| document_type | select | No | FT, FR, ORC, NC. Default: FT |
| fiscal_provider | select | No | billpt, fiskaly, sage. Auto-detected by country if empty |
| initial_status | select | No | pending (default) or completed |
| nif_attribute | text | No | Shopify note_attributes key where the customer NIF/VAT is stored. Default: nif |
| entity_source | text | No | Order source: shopify, manual, api. Default: shopify |
| assign_numbering | select | No | No (default): only stores portal and zone. Yes: also assigns the series number and sets completed (portals without a fiscal third party) |
| save_payload | select | No | Save full Shopify JSON in payload_json (up to 50KB). Default: Yes |
Credentials
Section titled “Credentials”Requires a sqlQuery credential (MySQL/MariaDB) with:
- host: Database host (e.g.
127.0.0.1) - user: Database user (e.g.
user_hubfiscal) - password: User password
- database: Hub Fiscal database name (e.g.
hubfiscal) - port: Port (default:
3306)
Field Mapping
Section titled “Field Mapping”The node maps Shopify order fields to Hub Fiscal automatically:
| Hub Fiscal field | Shopify source |
|---|---|
entity_id | data.id |
order_number | data.order_number → data.name |
country_iso | config → billing_address.country_code → PT |
type | config document_type → FT |
fiscal_provider | config → auto by country |
contact_name | billing_address.name |
contact_email | data.email |
contact_nif | note_attributes[nif_attribute].value |
total_net | data.subtotal_price |
total_tax | data.current_total_tax → data.total_tax |
total_gross | data.total_price |
currency | data.currency |
issued_at | data.created_at (date only) |
Provider Auto-detection
Section titled “Provider Auto-detection”When fiscal_provider is left empty, the node selects the provider based on country_iso:
| Country | Provider |
|---|---|
| PT, AO, MZ, CV | billpt |
| ES, DE, AT | fiskaly |
| Other | null (stored empty, fill manually later) |
NIF from note_attributes
Section titled “NIF from note_attributes”Shopify does not have a native NIF/VAT field. Configure your Shopify checkout to collect it as a note attribute and set nif_attribute to match the key name:
"note_attributes": [ { "name": "nif", "value": "PT999999990" }]Common key names: nif, vat, tax_id, nif_vat, numero_fiscal.
Upsert Behaviour
Section titled “Upsert Behaviour”The documents table has a unique constraint on (entity_id, entity_source, type). On Shopify webhook retries:
- If the document is still
pending: all fields are refreshed. - If the document is already
completedorfailed: status is preserved, only totals and payload update.
This ensures a re-delivered webhook never overwrites an already-fiscalized document.
Expected input: a Shopify Order object from a webhook or previous node:
{ "id": 6684429451477, "order_number": 14522, "name": "#14522", "email": "customer@example.com", "financial_status": "paid", "currency": "EUR", "subtotal_price": "63.56", "current_total_tax": "14.62", "total_price": "78.18", "created_at": "2026-04-20T10:00:00Z", "billing_address": { "name": "John Doe", "country_code": "PT" }, "note_attributes": [ { "name": "nif", "value": "PT999999990" } ]}Output
Section titled “Output”{ "success": true, "hub_document_id": 22, "entity_id": "6684429451477", "order_number": "14522", "country_iso": "PT", "type": "FT", "status": "pending", "fiscal_provider": "billpt", "contact_name": "John Doe", "contact_email": "customer@example.com", "contact_nif": "PT999999990", "total_net": 63.56, "total_tax": 14.62, "total_gross": 78.18, "currency": "EUR", "message": "Pedido Shopify #14522 registrado en Hub Fiscal (ID: 22)"}Typical Workflow
Section titled “Typical Workflow”Pattern 1 — Register then fiscalize:
Shopify Webhook → HubfiscalStoreShopify (pending) → BillptCreateInvoiceFromShopify → HubfiscalStoreBillpt (updates to completed)Pattern 2 — Register only (deferred fiscalization):
Shopify Webhook → HubfiscalStoreShopify (pending)Fiscalization is handled by a separate scheduled workflow that queries status = 'pending' from Hub Fiscal.
- The
fiscal_statustable records the initialregisteraction withstatus: pendingfor traceability. contact_nifis only populated if the Shopify order contains anote_attributematchingnif_attribute. If the NIF is stored elsewhere (metafields, tags), a preceding Transform node can move it intonote_attributesor use thecontact_niffield override.- The
issued_atdate is extracted fromcreated_at(date only, time is dropped).
Portal and numbering (daily aggregation to Sage X3)
Section titled “Portal and numbering (daily aggregation to Sage X3)”Besides storing the document, the node determines the sales portal (equivalenza.com, .it, .fr or .pt) from the order and the zone (Canary Islands, if the shipping postal code starts with 35 or 38), and stores them on the document. HubfiscalAggregateSales uses this to group the day’s sales.
With the Number and complete option set to Yes, on portals without a fiscal third party (equivalenza.com, .it and .fr) the node also:
- assigns the next sequential number of the series, with no leading zeros and no yearly reset (
FESH1,FESH2…), and - sets the document to
completed.
| Portal | Invoice | Credit note |
|---|---|---|
| equivalenza.com | FESH | AESH |
| equivalenza.com (Canary Islands) | FCAH | ACAH |
| equivalenza.it | FITH | AITH |
| equivalenza.fr | FFRH | AFRH |
- No gaps or duplicates, even when orders arrive at the same time: each series counter is locked while assigning, and an error does not consume the number.
- Idempotent: resending the same order does not renumber it.
- equivalenza.pt is not numbered here: Bill.pt does it (
FHPT/AHPT). - A type other than invoice or credit note (for example
ORC) or a portal with no rule is not numbered. - It is off by default (
No): only portal and zone are stored. Turn it on when you decide from which day numbering starts, because numbering consumes real series numbers.
It requires applying to the Hub Fiscal database the portal and zone columns and the document_sequences and portal_providers tables. If they are not applied, the node keeps working as before and does not number.
Extra node output with this data: portal, zone, fiscal_doc_number and numbering (the result: numerado, ya_numerado, numeracion_desactivada, delegado_en_billpt, esquema_no_aplicado…).
Related Nodes
Section titled “Related Nodes”- HubfiscalAggregateSales - Groups the day’s sales by portal and prepares them for Sage X3
- HubfiscalStoreBillpt - Update the record after Bill.pt creates the invoice
- BillptCreateInvoiceFromShopify - Create the Bill.pt invoice
- HubfiscalGetDocuments - Query pending orders for retry workflows
- HubfiscalUpdateDocument - Manually update a document record