Skip to content

Orders ​

Use order to sync commerce orders and the fiscal context Factulit needs to decide whether to create, cancel, or rectify an invoice.

For API connections, fiscal instructions are applied only after the connection owner enables invoicing through the Factulit consent wizard. Before that point orders and related customers/statuses are stored, but no invoice, cancellation or rectification is emitted. The invoice cutoff chosen in that wizard applies to order instructions; it does not limit direct invoices.

Minimal v1.0-Compatible Payload ​

json
{
  "id_external": "order-1001",
  "reference": "1001",
  "order_date": "2026-07-07 10:30:00",
  "total": 121,
  "total_tax": 21,
  "currency": "EUR",
  "status": "paid",
  "id_order_status": "paid",
  "source_platform": "custom",
  "fiscal_event": "invoice_candidate",
  "invoice_action": "create_invoice",
  "client": {
    "id_external": "customer-1001",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.test",
    "country": "ES"
  },
  "breakdown": [
    {
      "id_external_product": "sku-001",
      "name": "Product",
      "quantity": 1,
      "base_amount": 100,
      "tax_rate": 21,
      "tax_amount": 21
    }
  ]
}

Payment Date (v1.5, additive) ​

paid_at is the instant the store actually collected the payment (PSP capture, payment module confirmation, or the moment an administrator recorded the payment), as an RFC 3339 timestamp with offset:

json
{
  "order_date": "2026-09-07 10:15:00",
  "paid_at": "2026-09-07T10:15:42+02:00",
  "currency": "USD"
}

It is optional and additive within contract 1.5. When only one of order_date / paid_at is present, Factulit treats the other as the same instant, which is the usual checkout case; send both when they differ (bank transfer collected days later, cash on delivery). Omit the key when the store does not know the value.

Factulit uses it to pick the exchange rate of an order paid in a currency other than the euro: the last ECB reference rate published before the payment instant. It does not change any other fiscal decision.

Channel and Store Facts (v1.3+) ​

Two optional facts help Factulit classify each order into a billing profile when the account owner configures them (separate invoice series and issuing mode per commercial channel or per store):

  • source_channel (string, max 32): the commercial channel the order was born in, for example web or com. Lowercase recommended.
  • source_channel_evidence (string, key=value): where that channel came from in the source system, for example created_via=admin.
  • shop.id: multi-store installations should keep sending the store id of each order; it is stored with the order and can also classify it.

These fields are never fiscal instructions. If the connection has no billing profiles they are simply stored. If the owner has configured profiles, an order that does not match exactly one profile is held for manual classification and no invoice is issued for it — it is never numbered under another channel's series.

Sending orders is available to commerce connections and to API connections (x-api-key of an API connection). Each connection keeps its own id_external namespace, so identifiers from different systems never collide. Connection types that do not accept orders receive 403 with error_code: orders_not_supported_by_connection.

Connection Setup Gate (v1.4+) ​

New connections start in a guided 3-step setup. Until the account owner completes step 2 in Factulit, the order and client resources answer 423 with:

json
{
  "success": false,
  "error": "Connection is not configured yet: complete the setup in Factulit before syncing orders",
  "error_code": "sync_not_ready",
  "retryable": true
}

Treat it as a temporary, account-level condition: pause and retry later without burning per-order retries. The status and inventory resources stay open during setup — they are the input of step 2. API connections are exempt (their orders are deliberate instructions under their own consent). Connections created before this flow are grandfathered and never gated.

inventory resource (step 1) ​

Right after connecting, report the installation inventory so step 2 can show stores and volume before any order is synced:

http
POST /v1/inventory
{
  "stores": [
    {"id": "0", "name": "Main store", "url": "https://shop.example", "orders_count": 120}
  ],
  "orders_total": 120
}

stores[] accepts up to 100 entries (id required, max 32 chars; name, url and orders_count optional). The call is idempotent (upsert per store id). Single-store platforms may report one entry.

Setup fields in module-version (additive) ​

The module-version response now includes:

  • setup_state: pending_inventory, pending_configuration or configured.
  • sync_ready (bool): whether orders are accepted.
  • store_ids: comma-separated store ids selected in Factulit (step 2), "" meaning all stores, or null when the selection is not managed from Factulit. When not null, modules should mirror it into their local store selector; the same value travels as the store_ids query parameter of the pull callback. When null or absent, the local selector keeps ruling.

Unmapped Totals and the Nature of Discounts (v1.5+, v1.8) ​

unmapped_totals[] (v1.5+) carries any amount that participates in the order total but that the connector cannot translate into a fiscal line: a gift card redemption, store credit, a payment-method surcharge, or a third-party extension total. Each entry has a stable, lowercase code (for example store_credit), an optional title, and a signed value — the effect on the order total. The connector only records the fact; Factulit decides the tax treatment. An unlabelled code parks the order for review until the merchant declares its treatment in the billing profile.

json
{
  "unmapped_totals": [
    { "code": "store_credit", "title": "Customer balance", "value": -80, "kind": "customer_credit" }
  ]
}

Contract v1.8 adds an optional kind to both discounts[] entries and unmapped_totals[] entries, describing the commercial nature of the concept as observed by the connector:

  • promotional (default when absent): an ordinary commercial coupon.
  • customer_credit: a balance the store owes the customer (store credit, refund credit, wallet). Applied as a discount by default, unless the profile chooses to retain it for review.
  • gift_card: redemption of a previously sold gift card.
  • loyalty: the store's own reward points.
  • unknown: the connector cannot tell.

kind is a fact about the coupon's origin, never a fiscal instruction — Factulit still decides how each nature is taxed. For the sale side of a gift card, see breakdown[].line_kind: gift_voucher (v1.5).

v1.3 Correction Events ​

Set contract_version to 1.3 when you send correction_events[]. Use a stable id_external_event, describe the observed fact, its lines and signed deltas, and let Factulit retain the fiscal decision. Generic administrative edits must use event_type: "unknown" and never justify automatic issuance. Legacy refunds[] from v1.2 remains accepted and is normalized to explicit refund events.

Set contract_version to 1.4 to send optional tags[]. Matching is exact and case-insensitive after normalization. Tags describe the order; only rules confirmed by the account owner determine the fiscal action.

Existing v1.0 payloads remain valid without these fields.

Public API documentation for Factulit.