Data di scadenza del contratto (Contratti)

v2.7.0 · CRUD · Contratti e abbonamenti

Contratti

Leggere, creare, modificare ed eliminare contratti e abbonamenti con attributi, domini, cronologia dello stato e fatture associate. Lo stato viene modificato tramite un endpoint secondario dedicato.

GET    /Export/JSON/contracts
GET    /Export/JSON/contract/{id}
POST   /Import/JSON/contracts
PUT    /Import/JSON/contracts
PUT    /Import/JSON/contracts/{id}/status
DELETE /Delete/JSON/contract/{id}

Endpoint

MetodoEndpointAmbitoDescrizione
GET/Export/JSON/contractscontracts:readTutti i contratti, in ordine crescente per ID (con filtri)
GET/Export/JSON/contract/{id}contracts:readUn contratto; se non vengono trovati risultati, viene restituito un codice HTTP 200 con un data
GET/Export/JSON/contracts/{von}:{bis}, /contracts/{von}:contracts:readintervallo di ID o intervallo aperto
GET/Export/JSON/contracts/{id}contracts:read⚠️ Plurale: tutti i contratti a partire da questo ID, non solo uno
POST/Import/JSON/contractscontracts:writeCrea nuovi contratti
PUT/Import/JSON/contractscontracts:writeModifica contratti esistenti
PUT/Import/JSON/contracts/{id}/statuscontracts:writeModifica solo lo stato, con registrazione nella cronologia degli stati
DELETE/Delete/JSON/contract/{id}contracts:deleteEliminare un contratto, compresi attributi, domini e cronologia degli stati
DELETE/Delete/JSON/contractscontracts:deletePiù contratti tramite JSON-Rumpf {"data": [{"contracts_id": …}]}
Modificato nella v2.122.12: un intervallo va scritto come /contracts/{von}:{bis}. Fino alla v2.122.11, /contracts/10/20 restituiva comunque i contratti a partire da 10 senza limite massimo, mentre ora restituisce un errore HTTP 400 INVALID_RANGE, così come qualsiasi altro segmento che non sia un numero intero o un intervallo (/contract/10x, /contract/10.0). Gli spazi vuoti ai margini dell’ID non vengono conteggiati. Regole: API di esportazione, sezione «Segmento di percorso».

Filtro di query (GET)

ParametriDescrizioneEsempio
?status=ID di uno stato del contratto; gli stati del negozio sono riportati in contracts_statuses[] in ogni risposta?status=1
?customer_id=ID cliente?customer_id=42
?product_id=ID del prodotto?product_id=100
?interval=Fatturazione per anno: 1 annuale, 2 semestrale, 3 tre volte all'anno, 4 trimestrale, 6 sei volte all'anno, 12 mensile?interval=12
?date_from=, ?date_to=Data del contratto (contracts_date) da o fino a?date_from=2025-01-01
?active=1solo contratti senza data di disdetta inserita (contracts_cancellation_date_effective vuoto); anche una data di disdetta futura esclude il contratto?active=1

Più filtri agiscono in combinazione. Un valore non valido genera un errore HTTP 400 INVALID_FILTER_VALUE, ad esempio ?interval=5 (a partire dalla v2.122.10). A partire dalla v2.122.12, gli spazi vuoti ai margini non vengono conteggiati; un valore vuoto significa «non impostato».


Struttura dei dati

Ogni contratto presenta questi campi. I nomi dello stato e dell’articolo sono in tedesco.

SezioneCampi
ID e statocontracts_id, contracts_status_id, contracts_status_name
Clientecontracts_customers_id, customer_name, customer_email, contracts_customers_address_book_id, contracts_shipping_address_book_id
Articolo e prezzocontracts_products_id, product_name, product_model, contracts_products_quantity, contracts_products_tax, contracts_price, contracts_final_price, contracts_discount, contracts_use_current_price
Fatturazionecontracts_interval e contracts_period_interval (valori come ?interval=, ciascuno con un campo corrispondente …_text con la denominazione), contracts_months, contracts_next_order_date, contracts_payment_class
Periodicontracts_date; durata contracts_current_term_date_begin/_end, periodo di fatturazione contracts_current_period_date_begin/_end, ultima fatturazione contracts_last_billed_term_date_begin/_end e contracts_last_billed_period_date_begin/_end
Disdettacontracts_cancellation_date_received, contracts_cancellation_date_effective
Dominio e licenzacontracts_domain_id, contracts_domain_name, contracts_overwrite_domain, contracts_xolic_id
Variecontracts_comment, contracts_template, contracts_error_flag, contracts_is_standalone

Dati annidati

ElencoContenuto per ogni voce
attributes[]Caratteristiche dell’articolo contrattuale: contracts_products_attributes_id, contracts_products_id, products_options, products_options_values, options_values_price, detail_id
domains[]contracts_domains_id, contracts_domains_domain_name, contracts_domains_date_paid, contracts_domains_date_termination, contracts_domains_provider, contracts_domains_exclusive, contracts_domains_cost
status_history[]più recenti per primi: status_history_id, status_id, status_name, date_added, customer_notified, comments, user_id
orders[]fatture collegate, con il collegamento più recente per primo: orders_id, date_created, date_purchased, orders_status

Oltre a data, in ogni risposta è presente contracts_statuses[] con gli stati contrattuali del negozio, che hanno una denominazione in tedesco (status_id, status_name, status_label, status_active, status_is_default).


Importazione (POST/PUT)

  • POST crea un nuovo record e richiede contracts_customers_id e contracts_products_id di un cliente o di un articolo esistente. Se viene inviato un contracts_id già esistente, il record non viene creato.
  • PUT modifica e richiede l'contracts_id di un contratto esistente. Vengono modificati solo i campi inviati.
  • Sono modificabili i campi della struttura dati ad eccezione dei nomi e dei testi (contracts_status_name, customer_name, customer_email, product_name, product_model, contracts_domain_name, …_text). Se si invia un’esportazione, l’importazione li segnala come campi sconosciuti (UNKNOWN_FIELD), così come gli elenchi status_history[] e orders[] nonché gli identificatori contracts_products_attributes_id e contracts_products_id in attributes[] e contracts_domains_id in domains[]. L’importazione li ignora e compila i campi rimanenti; rimuovete questi campi prima di inviare nuovamente i dati, in modo che la risposta non contenga avvisi. I campi data come YYYY-MM-DD, i campi relativi ai periodi di fatturazione (…_period_date_…) come YYYY-MM-DD HH:MM:SS; null o lasciandoli vuoti li azzerano.
  • contracts_interval accetta solo 1, 2, 3, 4, 6 o 12; in caso contrario, il record viene rifiutato.
  • attributes[] products_options, , e , accettano la chiave senza . Nel caso di , un elenco inviato insieme alla richiesta sostituisce tutte le voci precedenti. products_options_values options_values_price detail_id domains[] contracts_domains_… contracts_domains_id PUT
  • status Come oggetto, {"status_id": …, "comments": "…", "customer_notified": 0} imposta lo stato e registra una voce nella cronologia degli stati. v2.122.13 Se status_id non è uno stato contrattuale del negozio (sezione «Stato contrattuale» in basso), non è un numero intero o manca, l’importazione salva il record senza lo stato e segnala l’avviso CONTRACT_STATUS_UNKNOWN; il record viene considerato creato o modificato.
  • contracts_status_id L’impostazione diretta sullo stato del contratto imposta lo stato senza inserire alcuna voce nella cronologia degli stati. v2.122.13 Un valore che non è uno stato contrattuale non viene salvato, mentre i campi rimanenti sì, con lo stesso avviso. Per una modifica dello stato con cronologia, utilizzare status o il sotto-endpoint /status.
  • ⚠️ Un valore impostato su « contracts_cancellation_date_effective » può avere effetto alla successiva esecuzione della risoluzione automatica del contratto.

Esempio

curl -s -X POST "https://shop.de/xpanel/xoport/Import/JSON/contracts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "contracts",
    "data": [{
      "contracts_customers_id": 42,
      "contracts_products_id": 100,
      "contracts_interval": 12,
      "contracts_price": "29.90",
      "contracts_date": "2026-11-01",
      "attributes": [
        {"products_options": "Lizenztyp", "products_options_values": "Enterprise"}
      ],
      "domains": [
        {"contracts_domains_domain_name": "kunde.de"}
      ],
      "status": {"status_id": 1, "comments": "Angelegt per API"}
    }]
  }'

Modifica dello stato (PUT)

PUT /Import/JSON/contracts/{id}/status con l’ambito contracts:write. È obbligatorio specificare status_id, oltre a comments e customer_notified(facoltativi). Senza status_id si ottiene un errore HTTP 400 MISSING_FIELD; per un status_id che non corrisponda a uno stato contrattuale del negozio o a un numero intero, si ottiene un errore HTTP 400 INVALID_STATUS con gli ID validi riportati in error.valid_status_ids (a partire dalla v2.122.13, sezione «Stato del contratto») e, per un contratto sconosciuto, HTTP 404 NOT_FOUND. In tutti e tre i casi il contratto rimane invariato.

curl -s -X PUT "https://shop.de/xpanel/xoport/Import/JSON/contracts/1/status" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status_id": 3, "comments": "Kündigung per API", "customer_notified": 0}'

# Antwort
{
  "success": true,
  "type": "contracts_status",
  "contracts_id": 1,
  "previous_status_id": 1,
  "new_status_id": 3,
  …
}

Se il contratto ha una data di risoluzione valida, la risposta riporta inoltre warning: la risoluzione automatica del contratto può sovrascrivere lo stato in un secondo momento.


Stato del contratto v2.122.13

Per status_id, status.status_id e contracts_status_id è valido qualsiasi stato del contratto del negozio: gli stati della tabella status con type = 'contracts', da cui attinge anche il backend, in ogni lingua, compresi quelli disattivati (status_active = 0); questi ultimi nascondono solo la selezione nel backend. Gli stati dell’ordine (/order_statuses) non sono stati contrattuali. Gli ID validi variano a seconda del negozio: consultateli su contracts_statuses[], su GET /Export/JSON/contracts o su error.valid_status_ids. contracts_statuses[] elenca solo gli stati con denominazione in tedesco; uno stato senza denominazione in tedesco è comunque valido.

L’ID è un numero intero, espresso come cifra singola o sequenza di cifre (54, "54"; gli spazi in margine non contano). true, [65], "54abc", "1e3", 54.9 o 54.0 non sono ID.

Modalità di invioStato del contratto non valido
PUT /Import/JSON/contracts/{id}/statusHTTP 400 INVALID_STATUS, error.valid_status_ids indica gli ID validi; il contratto rimane invariato
Importazione del contratto, status.status_id (anche status senza status_id, ad esempio "status": 54 o "status": {})Record scritto, stato e cronologia dello stato invariati, avviso CONTRACT_STATUS_UNKNOWN con field = status.status_id o status; "status": null è considerato non inviato
Importazione del contratto, contracts_status_idcampo non compilato (rimane vuoto al momento della creazione), altri campi compilati, avviso CONTRACT_STATUS_UNKNOWN con field = contracts_status_id
HTTP 400
{
  "success": false,
  "api_version": "2.122.13",
  "error": {
    "code": "INVALID_STATUS",
    "message": "status_id 1 is not a contract status. Valid: 7, 3, 12 (…)",
    "valid_status_ids": [7, 3, 12]
  }
}

Nell’importazione del contratto, il record continua a essere conteggiato come inserted o updated. L’avviso è presente in warnings[] nella risposta e nella voce del record in records[]:

"warnings": [
  {
    "type": "CONTRACT_STATUS_UNKNOWN",
    "field": "status.status_id",
    "entity": "contracts",
    "contracts_id": 42,
    "message": "Contract 42: status.status_id ignored — status.status_id 1 is not a contract status. Valid: 7, 3, 12 (…)",
    "first_occurrence": "record 1"
  }
]
Modificato nella v2.122.13: fino alla v2.122.12, il sotto-endpoint /status e l’oggetto status effettuavano un controllo incrociato con gli stati dell’ordine (orders_status). Uno stato del contratto che non fosse presente anche come stato dell’ordine generava un errore HTTP 400 nel sotto-endpoint e veniva silenziosamente ignorato durante l’importazione; un ID presente solo come stato dell’ordine veniva scritto come stato del contratto nell’endpoint con il nome dello stato dell’ordine in new_status_name. contracts_status_id veniva scritto senza essere verificato ("abc" come 0, true come 1), mentre valori come "1e3" o 54.9 venivano considerati rispettivamente come 1000 e 54. ⚠️ Chi invia gli ID dello stato dell’ordine come stato del contratto riceverà ora un codice di errore HTTP 400 o l’avviso: utilizzare gli ID disponibili su contracts_statuses[]. new_status_name ora riporta il nome dello stato del contratto.

Eliminazione (DELETE)

Vengono eliminati il contratto, i suoi attributi e domini, la cronologia dello stato e i collegamenti a fatture e progetti. Le fatture e i progetti stessi rimangono.

Nessun blocco in caso di fatture in sospeso: il contratto viene eliminato anche se vi sono fatture ad esso collegate o ancora in sospeso, come avviene per l’eliminazione nel backend. Successivamente il collegamento verrà meno e un addebito tramite mandato SEPA non potrà più raggiungere tali fatture. Verificare preventivamente le fatture: quelle collegate sono elencate in orders[] da GET /Export/JSON/contract/{id}, ciascuna con il proprio stato d’ordine orders_status. Per verificare se uno stato è considerato pagato, consultare is_paid in GET /Export/JSON/order_statuses (Ordini, sezione «Dati anagrafici stato d’ordine»).
# Ein Vertrag
curl -s -X DELETE "https://shop.de/xpanel/xoport/Delete/JSON/contract/1" \
  -H "Authorization: Bearer $TOKEN"

# Mehrere Verträge
curl -s -X DELETE "https://shop.de/xpanel/xoport/Delete/JSON/contracts" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": [{"contracts_id": 1}, {"contracts_id": 2}]}'
  • Un contratto sconosciuto genera un errore HTTP 404 NOT_FOUND se richiamato singolarmente. In caso di elaborazione in batch, gli ID cancellati si trovano in deleted_ids, quelli non trovati in errors[].
  • Un URL troncato senza data[].contracts_id, ad esempio {"ids": [1, 2]}, non cancella nulla e restituisce un errore HTTP 400 MISSING_DATA.

Ambiti OAuth2

AmbitoAutorizzazione
contracts:readLeggere i contratti
contracts:writeCreare e modificare contratti, compreso lo stato
contracts:deleteEliminare contratti