Concessionaria

Stock veicoli, vendite e report.

8 endpoint Versione v1 · revisione 2026-09-05

Gli endpoint sono relativi a https://api.officina.it e richiedono l'header Authorization: Bearer con la chiave API e X-API-Version: 2026-09-05. L'header della revisione è obbligatorio: differenza fra v1 e revisione.

GET /v1/vehicle-sales
Permesso richiesto reports.read

Elenca le vendite veicoli

Le vendite di veicoli, con margine (total_profit) e riferimento alla fattura emessa.
Risposte
200
Le vendite veicoli.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
422
Un campo della richiesta manca o non è valido: «param» indica quale.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-sales \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
Risposta
{
  "object": "list",
  "data": [
    {
      "object": "vehicle_sale",
      "id": "5b9d3e70-2c41-48a6-9e15-7f2a6c8b4d13",
      "seq_number": 24,
      "status": "delivered",
      "customer_id": "4c911f08-7713-4e83-bdf6-a0692a1b43fd",
      "customer_name": "Mario Rossi",
      "vehicle_name": "Fiat Panda",
      "vehicle_license": "AB123CD",
      "sale_date": "2026-06-19",
      "total_after_tax": 6500.0,
      "total_profit": 1820.0,
      "invoice_id": "4412e7b9-0c35-4a18-92d7-5b6ea1f38c04",
      "comments": null
    }
  ],
  "has_more": false,
  "url": "/v1/vehicle-sales",
  "date_filter": {
    "object": "date_filter",
    "preset": "year",
    "from": "2026-01-01",
    "to": "2026-12-31"
  }
}
GET /v1/vehicle-sales/status-counts
Permesso richiesto reports.read

Conta le vendite per stato

Il numero di vendite in ciascuno stato, con gli stessi filtri dell'elenco.
Risposte
200
Il numero di vendite per stato.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-sales/status-counts \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
Risposta
{
  "object": "vehicle_sale_status_counts",
  "draft": 1,
  "signed": 2,
  "delivered": 21,
  "date_filter": {
    "object": "date_filter",
    "preset": "year",
    "from": "2026-01-01",
    "to": "2026-12-31"
  }
}
GET /v1/vehicle-sales/{id}
Permesso richiesto reports.read

Recupera una vendita veicolo

Restituisce la singola vendita con tutte le sezioni del dettaglio: righe di ricavo e di costo, il costo di acquisto del veicolo, il margine, i giorni di giacenza, gli allegati, il veicolo e la fattura collegata. Il margine è total_profit: è il valore memorizzato che leggono anche i report e la Situazione concessionaria. Non è total_revenue meno i due costi — quella colonna scorpora l'IVA dalle righe di ricavo accessorie. Va mostrato, mai ricalcolato, altrimenti il dato non coincide con le altre schermate. vehicle e invoice valgono null se la relativa lettura fallisce: una vendita il cui acquisto o la cui fattura non sono leggibili resta comunque consultabile. Il 404 copre sia un id inesistente sia uno di un'altra officina.
Risposte
200
La vendita richiesta.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
404
La risorsa non esiste, è stata eliminata o non appartiene alla tua officina.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-sales/{id} \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
Risposta
{
  "object": "vehicle_sale",
  "id": "5b9d3e70-2c41-48a6-9e15-7f2a6c8b4d13",
  "seq_number": 24,
  "status": "delivered",
  "customer_id": "4c911f08-7713-4e83-bdf6-a0692a1b43fd",
  "customer_name": "Mario Rossi",
  "vehicle_name": "Fiat Panda",
  "vehicle_license": "AB123CD",
  "sale_date": "2026-06-19",
  "total_after_tax": 6500.0,
  "total_profit": 1820.0,
  "invoice_id": "4412e7b9-0c35-4a18-92d7-5b6ea1f38c04",
  "comments": null,
  "vehicle_stock_id": "3e9a7c12-5b48-40d6-8f27-1c4b9e2a6d35",
  "sold_by_name": "Luca Bianchi",
  "created_at": "2026-06-19T09:12:44Z",
  "total_before_tax": 6450.0,
  "total_tax": 50.0,
  "total_discount": 0.0,
  "total_revenue": 6500.0,
  "total_sale_costs": 0.0,
  "vehicle_total_cost": 4680.0,
  "margin_percent": 28.0,
  "days_in_stock": 92,
  "revenue_line_items": [
    {
      "object": "vehicle_sale_revenue_line_item",
      "id": "9f1b2c34-6d78-4e90-a1b2-c3d4e5f60718",
      "category": "vehicle",
      "description": "Vendita Fiat Panda",
      "tax_rate": 0,
      "vat_code": "N5",
      "amount": 6500.0
    }
  ],
  "cost_line_items": [],
  "documents": [
    {
      "object": "vehicle_sale_document",
      "id": "71c8d9e0-2f31-4a52-b6c7-8d9e0f1a2b3c",
      "name": "contratto.pdf",
      "content_type": "application/pdf",
      "description": null,
      "url": "/v1/vehicle-sales/5b9d3e70-2c41-48a6-9e15-7f2a6c8b4d13/documents/71c8d9e0-2f31-4a52-b6c7-8d9e0f1a2b3c/download",
      "file_size_bytes": 184320,
      "created_at": "2026-06-19T09:20:03Z"
    }
  ],
  "vehicle": {
    "object": "dealership_vehicle",
    "id": "8821f0ac-5d2b-41e7-9a10-6c3f2b7d4e55",
    "name": "Fiat Panda",
    "manufacturer_name": "Fiat",
    "model": "Panda",
    "license": "AB123CD",
    "vin": "ZFA31200003456789",
    "km": 82000,
    "registered_at": "2018-03-12"
  },
  "invoice": {
    "object": "dealership_invoice",
    "id": "4412e7b9-0c35-4a18-92d7-5b6ea1f38c04",
    "seq_number": 118,
    "issued_at": "2026-06-20"
  }
}
GET /v1/vehicle-sales/{id}/documents/{documentID}/download
Permesso richiesto reports.read

Scarica un allegato della vendita

Restituisce i byte di un allegato elencato in documents nel dettaglio della vendita. Il percorso di archiviazione è privato: il file viene letto lato server e restituito con il proprio content type. L'allegato deve appartenere sia alla vendita indicata nel path sia all'officina chiamante: controllare solo l'officina permetterebbe di usare l'id di una vendita per scaricare l'allegato di un'altra. Caricamento ed eliminazione restano sul web.
Risposte
200
Il file richiesto.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
404
La risorsa non esiste, è stata eliminata o non appartiene alla tua officina.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-sales/{id}/documents/{documentID}/download \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
GET /v1/vehicle-stocks
Permesso richiesto reports.read

Elenca i veicoli in stock

I veicoli acquistati per la rivendita, con costo di acquisto, costo totale sostenuto e giorni di giacenza. La concessionaria rientra nel permesso reports, non ne ha uno proprio.
Risposte
200
I veicoli in stock.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
422
Un campo della richiesta manca o non è valido: «param» indica quale.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-stocks \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
Risposta
{
  "object": "list",
  "data": [
    {
      "object": "vehicle_stock",
      "id": "3e9a7c12-5b48-40d6-8f27-1c4b9e2a6d35",
      "seq_number": 18,
      "vehicle_id": "8821f0ac-5d2b-41e7-9a10-6c3f2b7d4e55",
      "vehicle_name": "Fiat Panda",
      "vehicle_license": "AB123CD",
      "purchase_date": "2026-05-04",
      "purchase_cost": 4200.0,
      "total_cost": 4680.0,
      "sale_price": 6500.0,
      "days_in_stock": 92,
      "sold": false
    }
  ],
  "has_more": false,
  "url": "/v1/vehicle-stocks"
}
POST /v1/vehicle-stocks
Permesso richiesto reports.write

Registra un acquisto veicolo

Registra un nuovo acquisto veicolo. Crea anche il VEICOLO corrispondente: un mezzo destinato al piazzale è per definizione nuovo per l'officina, quindi non esiste un veicolo a cui puntare — per questo i dati identificativi (manufacturer_id, model, license, vin, registered_at) stanno in questo corpo e non in un vehicle_id. purchase_cost e total_cost non si inviano: si ricavano da line_itemspurchase_cost somma le righe con categoria "purchase", total_cost le somma tutte, come fa il form web. Inviare totali propri farebbe divergere i valori memorizzati dalle righe che li spiegano, perciò i campi non riconosciuti vengono rifiutati. Anche line_items[].tax_rate è assente: le righe di acquisto sono memorizzate con aliquota 0 e total_cost è la somma lorda, quindi un'aliquota non cambierebbe nulla. Richiede il modulo Concessionaria (altrimenti 403). purchase_date non può essere nel futuro; la data odierna è accettata. La targa viene normalizzata in maiuscolo. Attenzione allo scope: la concessionaria non ha un permesso proprio e ricade in reports, quindi questa scrittura richiede reports.write — che qui non scrive un report, registra un acquisto. La modifica di un acquisto e l'intero ciclo di vita della vendita restano sul web. Restituisce 201 con lo stesso payload di GET /v1/vehicle-stocks/{id}. L'acquisto creato non comparirà in GET /v1/vehicle-stocks se in seguito gli verrà associata una vendita: quell'elenco contiene solo i veicoli ancora disponibili.
Risposte
201
L'acquisto appena registrato.
400
Corpo della richiesta non leggibile o JSON non valido.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
422
Un campo della richiesta manca o non è valido: «param» indica quale.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl -X POST https://api.officina.it/v1/vehicle-stocks \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05" \
  -H "Content-Type: application/json" \
  -d '{
  "manufacturer_id": "9c2e6b41-70a3-4d18-8f52-1b7d3c9a4e60",
  "model": "Giulietta",
  "license": "ZZ999ZZ",
  "vin": "ZAR94000007654321",
  "registered_at": "2019-04-10T00:00:00Z",
  "purchase_date": "2026-08-01T00:00:00Z",
  "supplier_id": "6d5c4b3a-2918-4706-b5c4-d3e2f1a09b87",
  "comments": "Ritirata da permuta",
  "vehicle_sale_price": 9500.0,
  "line_items": [
    {
      "category": "purchase",
      "description": "Acquisto Giulietta",
      "amount": 6000.0
    },
    {
      "category": "bodywork",
      "description": "Ritocco portiera",
      "amount": 450.5
    }
  ]
}'
GET /v1/vehicle-stocks/{id}
Permesso richiesto reports.read

Recupera un acquisto veicolo

Il dettaglio dell'acquisto. Aggiunge alla riga di elenco le voci di costo che compongono total_cost, il fornitore, il veicolo, gli allegati e la vendita con cui il mezzo è uscito, se venduto. A differenza dell'elenco, qui si risolve anche un acquisto già venduto: è l'unico modo per raggiungerlo, dato che l'elenco li esclude. sold è true quando esiste una vendita collegata. L'elenco ricava lo stesso flag da vehicle_stocks.sold_by, che il flusso di vendita non valorizza sempre: il dettaglio riporta il dato più affidabile. sale non è la riga completa della vendita: la query per acquisto non legge total_after_tax, quindi vengono esposti solo i campi effettivamente valorizzati. Per gli importi completi seguire sale.id. Il 404 copre sia un id inesistente sia uno di un'altra officina.
Risposte
200
L'acquisto richiesto.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
404
La risorsa non esiste, è stata eliminata o non appartiene alla tua officina.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-stocks/{id} \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"
Risposta
{
  "object": "vehicle_stock",
  "id": "3e9a7c12-5b48-40d6-8f27-1c4b9e2a6d35",
  "seq_number": 18,
  "vehicle_id": "8821f0ac-5d2b-41e7-9a10-6c3f2b7d4e55",
  "vehicle_name": "Fiat Panda",
  "vehicle_license": "AB123CD",
  "purchase_date": "2026-05-04",
  "purchase_cost": 4200.0,
  "total_cost": 4680.0,
  "sale_price": 6500.0,
  "days_in_stock": 92,
  "sold": true,
  "supplier_id": "6d5c4b3a-2918-4706-b5c4-d3e2f1a09b87",
  "supplier_name": "Autoparco Bergamo",
  "sold_by_name": "Luca Bianchi",
  "comments": null,
  "created_at": "2026-05-04T08:31:17Z",
  "line_items": [
    {
      "object": "vehicle_stock_line_item",
      "id": "a1b2c3d4-e5f6-4708-9a0b-1c2d3e4f5061",
      "category": "purchase",
      "description": "Acquisto Fiat Panda",
      "tax_rate": 0,
      "vat_code": null,
      "amount": 4200.0
    },
    {
      "object": "vehicle_stock_line_item",
      "id": "b2c3d4e5-f607-4819-a0b1-2c3d4e5f6072",
      "category": "bodywork",
      "description": "Ritocco paraurti",
      "tax_rate": 22,
      "vat_code": null,
      "amount": 480.0
    }
  ],
  "documents": [],
  "vehicle": {
    "object": "dealership_vehicle",
    "id": "8821f0ac-5d2b-41e7-9a10-6c3f2b7d4e55",
    "name": "Fiat Panda",
    "manufacturer_name": "Fiat",
    "model": "Panda",
    "license": "AB123CD",
    "vin": "ZFA31200003456789",
    "km": 82000,
    "registered_at": "2018-03-12"
  },
  "sale": {
    "object": "vehicle_sale_link",
    "id": "5b9d3e70-2c41-48a6-9e15-7f2a6c8b4d13",
    "seq_number": 24,
    "status": "delivered",
    "customer_id": "4c911f08-7713-4e83-bdf6-a0692a1b43fd",
    "customer_name": "Mario Rossi",
    "sale_date": "2026-06-19",
    "sale_price": 6500.0,
    "total_profit": 1820.0
  }
}
GET /v1/vehicle-stocks/{id}/documents/{documentID}/download
Permesso richiesto reports.read

Scarica un allegato dell'acquisto

Restituisce i byte di un allegato elencato in documents nel dettaglio dell'acquisto, con le stesse regole della variante per la vendita: lettura lato server del percorso privato, content type originale, e l'allegato deve appartenere sia all'acquisto indicato nel path sia all'officina chiamante. Caricamento ed eliminazione restano sul web.
Risposte
200
Il file richiesto.
401
Chiave API mancante, non valida, revocata o scaduta.
402
Il piano non include l'accesso API, oppure non è attivo un abbonamento.
403
La chiave non ha il permesso richiesto per questa operazione.
404
La risorsa non esiste, è stata eliminata o non appartiene alla tua officina.
500
Errore imprevisto del server. Il dettaglio finisce nei log, non nella risposta.
Richiesta
curl https://api.officina.it/v1/vehicle-stocks/{id}/documents/{documentID}/download \
  -H "Authorization: Bearer ofk_live_LA_TUA_CHIAVE" \
  -H "X-API-Version: 2026-09-05"