Omniflow / API

API

Ricevi in tempo reale le vendite di un negozio che usa Omniflow POS. Ti serve una chiave, che ti consegna il negozio stesso: da lì fai tutto da solo.

https://pos.omniflow.it/api/v1 Autenticazione Bearer Versione 1 · 27 agosto 2026

Fatti dare la chiave

Il negozio la genera dal proprio pannello, in Impostazioni → Integrazioni, e te la manda. Comincia con omf_live_ e si vede una volta sola: se va persa, il negozio ne genera un'altra e la vecchia smette di valere.

Per controllare che funzioni:

GET /v1/mecurl
curl https://pos.omniflow.it/api/v1/me \
  -H "Authorization: Bearer omf_live_..."

{
  "integration": "Delera",
  "account": "Sartoria Carillo",
  "webhook_url": null,
  "events": ["vendita.chiusa"]
}

Registra il tuo indirizzo

Una chiamata sola. Nella risposta arriva il segreto con cui firmiamo ogni consegna: si vede lì e mai più, quindi conservalo subito.

POST /v1/webhookscurl
curl -X POST https://pos.omniflow.it/api/v1/webhooks \
  -H "Authorization: Bearer omf_live_..." \
  -H "content-type: application/json" \
  -d '{"url": "https://tuo-dominio.it/omniflow"}'

{
  "url": "https://tuo-dominio.it/omniflow",
  "secret": "il-segreto-per-verificare-la-firma",
  "events": ["vendita.chiusa"],
  "signature_header": "x-omniflow-signature",
  "event_header": "x-omniflow-event"
}

Solo indirizzi https. Ripetendo la chiamata si registra un indirizzo nuovo e si riceve un segreto nuovo: quello vecchio non vale più. GET /v1/webhooks dice cosa risulta registrato, DELETE /v1/webhooks stacca tutto.

Gli eventi disponibili sono vendita.chiusa, attivo di suo, e vendita.annullata, che il negozio può accendere. Il nome dell'evento viaggia nell'intestazione x-omniflow-event, mai nel corpo.

Ricevi le vendite

Alla chiusura di ogni scontrino chiamiamo il tuo indirizzo. Nessun invio giornaliero, nessuna coda da interrogare: JSON piatto, con una sola eccezione — items, le righe dello scontrino.

La consegnaal tuo indirizzo
POST https://tuo-dominio.it/omniflow
content-type: application/json
x-omniflow-event: vendita.chiusa
x-omniflow-signature: sha256=<hmac del corpo>

{
  "order_id": "9f1c2b7e-3f4a-4c21-9b77-2f0a1d8e5c33",
  "customer_name": "Mario Rossi",
  "customer_email": "mario.rossi@esempio.it",
  "customer_phone": "+39 333 1234567",
  "service_type": "sarta",
  "total": 120.50,
  "status": "completato",
  "created_at": "2026-09-01T10:32:14.000Z",
  "items": [
    {
      "descrizione": "Giacca sartoriale",
      "quantita": 1,
      "prezzo": 120.50,
      "taglia": "48",
      "sku": "GIA-48",
      "barcode": "8012345678901",
      "categoria": "Sartoria",
      "tag": ["servizio"]
    }
  ]
}
CampoTipoNote
order_idstringSempre presente. Identificativo univoco dello scontrino: è la chiave su cui deduplicare.
customer_namestringSempre presente. Senza anagrafica la vendita non parte affatto.
customer_emailstringPresente se il cliente ne ha una. Almeno uno fra i due recapiti c'è sempre.
customer_phonestringPresente se il cliente ne ha uno.
service_typestringSempre valorizzato. Vedi sotto.
totalnumberTotale incassato, in euro con due decimali.
statusstringcompletato, oppure annullato se il negozio accende quell'evento.
created_atstringISO 8601 in UTC.
itemsarrayLe righe dello scontrino: cosa ha comprato il cliente. Assente se lo scontrino non ne ha.
items[].descrizionestringSempre presente. Il nome dell'articolo come sta sullo scontrino.
items[].quantitanumberSempre presente.
items[].prezzonumberSempre presente. Prezzo unitario in euro, non il totale di riga.
items[].tagliastringLa variante venduta. Presente se l'articolo ne ha una.
items[].skustringPresente se l'articolo ne ha uno.
items[].barcodestringPresente se l'articolo ne ha uno.
items[].categoriastringLa categoria di catalogo. Un livello solo: non c'e' una macrocategoria.
items[].tagarrayI tag di catalogo dell'articolo.
Un livello solo di categoria

Il catalogo Omniflow ha una categoria per articolo, piu i tag: non esiste una macrocategoria sopra di essa. Se il tuo gestionale ne vuole due livelli, scrivici: va deciso insieme quale dei due esce da categoria e quale dai tag.

Tipo di servizio

Ogni vendita porta un tipo di servizio. Il valore parte esattamente com'è definito: minuscolo, senza accenti, senza traduzione — non lo normalizziamo mai. I valori ammessi sono questi tre, uguali per tutti i punti vendita collegati:

ValoreSignificato
standardVendita normale, senza lavorazione
sartaArticolo venduto con un intervento di modifica su misura del cliente
su_misuraArticolo realizzato su misura per il cliente

Quale dei tre esce lo decide ogni negozio dal proprio pannello, associando a ognuno le categorie o le etichette del suo catalogo: due punti vendita diversi arrivano allo stesso valore per strade diverse, e ognuno usa quelli che gli servono. Una vendita che non corrisponde a nessuna regola parte come standard.

Verificare la firma

Ogni consegna porta x-omniflow-signature: l'HMAC-SHA256 del corpo, in esadecimale, calcolato con il segreto ricevuto alla registrazione. Firma il corpo grezzo, non il JSON riserializzato: uno spazio di differenza e la firma non torna.

VerificaNode.js
import { createHmac, timingSafeEqual } from 'node:crypto'

function firmaValida(corpoGrezzo, intestazione, segreto) {
  const attesa = createHmac('sha256', segreto).update(corpoGrezzo).digest('hex')
  const data = String(intestazione).replace(/^sha256=/, '')
  const a = Buffer.from(attesa)
  const b = Buffer.from(data)
  return a.length === b.length && timingSafeEqual(a, b)
}

Chi preferisce qualcosa di più semplice può chiedere al negozio di configurare una API key o un Bearer token al posto della firma: li mandiamo in un'intestazione a scelta.

Come ci comportiamo

Idempotenza

Lo stesso scontrino non viene mai trasmesso due volte: la chiave è order_id. Se lo ricevi due volte per un nostro ritentativo, scarta il secondo.

Ritentativi

Se non rispondi o rispondi con un errore, la transazione resta registrata da noi con il suo payload e viene ritentata automaticamente alle vendite successive, per sette giorni. Il negozio può anche ripeterla a mano dal pannello.

Tempo di risposta

Chiudiamo la richiesta dopo cinque secondi. Oltre quel limite la consideriamo fallita e la ritentiamo: alla cassa c'è un cliente che aspetta lo scontrino, e non può aspettare il tuo server.

Vendite senza anagrafica

Molti scontrini al banco non hanno un cliente registrato. Senza nome e senza recapito non li inviamo: restano segnati da noi come ignorati. Se li vuoi comunque, il negozio può abilitarli.

Cosa risponderci

  • 2xx — consegnata, non ritentiamo.
  • 4xx — payload rifiutato: non ritentiamo e segnaliamo l'errore nel pannello del negozio. Un corpo con il motivo aiuta a capire cosa correggere.
  • 5xx o nessuna risposta — problema temporaneo: ritentiamo.

Rileggere le transazioni

Se eri spento, o preferisci controllare invece di aspettare, le vendite già trasmesse si rileggono in qualsiasi momento.

GET /v1/transactionscurl
curl "https://pos.omniflow.it/api/v1/transactions?since=2026-09-01T00:00:00Z&limit=50" \
  -H "Authorization: Bearer omf_live_..."

{
  "data": [ { "order_id": "...", "service_type": "sarta", "...": "..." } ],
  "has_more": false
}

Ordine dal più recente. Ogni voce porta anche delivery_status e sent_at, così sai se quella consegna era andata a buon fine.

Se qualcosa non torna

  • 401 su ogni chiamata — la chiave è stata revocata o rigenerata: chiedine una nuova al negozio.
  • 429 con Retry-After: 60 — hai superato le 120 chiamate al minuto concesse a una chiave. È il freno contro l'integrazione che va in ciclo: aspetta il minuto e riprendi. Se ti serve di più, scrivici.
  • Non arriva niente — verifica con GET /v1/webhooks che l'indirizzo registrato sia quello giusto, e che risponda a un POST in meno di cinque secondi.
  • La firma non torna — quasi sempre è il corpo riserializzato: firma la stringa esatta ricevuta, prima di qualsiasi parsing.
  • Vedi solo alcune vendite — quelle senza anagrafica cliente non partono, salvo che il negozio le abiliti.
Il pannello del negozio è la fonte più veloce

Il negozio vede ogni consegna con esito, errore e payload, e può ripetere quelle fallite. Prima di scriverci, chiedigli cosa risulta lì.