API pe' gestionali esterni

Versione v1 — documentazione aggiurnata a 'o 29 luglio 2026

Chesta paggena documenta 'e API HTTP ca VolleyFriends mette a disposizione d''e gestore 'e strutture pe' tené 'o calannario d''e campe in sincrono cu 'nu software gestionale esterno o cu 'nu sito cu prenotazione online. Songo 'e stesse regole 'e dominio d''o pannello gestore (conflitte, chiusure, listino): cagna sulo 'o modo 'e se autenticà.

1. Che cosa permetteno 'e API

Cu 'na chiave API puoie, d'o software tujo, leggere e scrivere 'ncopp'ô calannario d'e strutture toie:

  • leggere strutture e campe cu 'e identificative d'e lloro, necessarie pe' tutte l'ati chiammate;
  • leggere 'e prenotazzioni 'e 'nu periodo, 'e 'na struttura o 'e 'nu campo sulo, pe' l'allineà a l'archivio tujo;
  • crià prenotazzioni da fora (pe' essempio quanno 'nu cliente prenota d'o sito tujo), cu 'e stessi cuntrolle 'e sovrapposizzione e chiusura d'o pannello;
  • modificà o scancellà 'na prenotazzione ca già ce sta (spustamento 'e orario o 'e campo, incasso, note, annullamento);
  • leggere 'a dispunibilità 'e 'nu campo dint'a 'nu juorno: slot già occupate, orarie 'e apertura e chiusure straordinarie, accussì da prupone 'e slot libbere senza replicà 'e regole;
  • leggere 'o listino 'e 'nu campo pe' ammustrà 'e priezze ô cliente finale.
Ambito d' 'e chiavi

Ogni chiave è legata all'account gestore ca l'ha criata e vede sulo 'e strutture, 'e campe e 'e prenotaziune 'e chillu account. 'Na risorsa ca appartiene a n'ato gestore nun risponne 403 ma 404 not_found: nun ne vene svelata l'esistenza.

Nun fanno parte 'e chesti API 'e richieste d' 'e organizzature pe' l'uso d' 'e campe dint'ê turnee (s'approvano dall'app), 'a criazione 'e strutture e campe, 'o sarvaggio 'e orarie, chiuse e listino: so' operaziune d' 'o pannello gestore.

2. Requisiti e attivazzione

  1. Un account gestore campe VolleyFriends cu' ammeno 'na struttura e 'nu campo.
  2. 'Nu abbonamento in corso cu' 'nu piano ca include 'a funzione «API pe' gestionali esterni». L'intera v1pure 'e sole letture — è riservata a chi tene chesta funzione: è 'na funzione vennuta, no 'nu accessorio d' 'o pannello.
  3. 'Na chiave API generata d' 'o gestionale: admin.volleyfriends.comImpostaziuneChiavi APIChiave nova.

'A chiave tene 'a forma vfk_ seguito da 40 caratteri esadecimali (44 caratteri in tutto) e vene ammustrata 'na vota sola, sùbbeto doppo 'a criazione: dint'ô database resta sulo l'impronta soja sha256, quinni nun è recuperabile 'n nisciuno modo. Se 'a pierde, revocala e generane 'na nova. Dint'all'elenco d' 'o pannello vide sulo 'o prefisso (es. vfk_9f2c), 'a data 'e criazione e chella d' 'o l'urdemo utilizzo.

3. Autenticazzione

Ogni richiesta va autenticata cu' l'header X-Api-Key. Nun servono token, login, scadenze o rinnovi: 'a chiave resta valida finché nun 'a revochi.

# 'E chiavi 'e chesta pagina so' d'esempio: sostituisci cu' 'a toja.
curl -s https://www.volleyfriends.com/api/manager-api/v1/venues   -H "X-Api-Key: vfk_9f2c41a7b83d05e6c19af4728b60d35e1c9a7f42"

Dint'all'esempi ca venono appriesso 'a chiave è letta d' 'a variabile d'ambiente VF_API_KEY, comme conviene fa' pure in produzione.

Header assente, cchiù curto 'e 12 caratteri, scanusciuto o ca appartiene a 'na chiave revocata: 'a risposta è 401 cu' chistu corpo.

{
  "error": "invalid_key",
  "message": "Chiave API mancante o non valida (header X-Api-Key)."
}
Custodia d' 'a chiave
  • 'A chiave vale comm'a 'na password cu' chini putere 'ncopp'ô calendario d' 'e strutture toje: nun 'a nzerì dint'a pagine, app o JavaScript lato browser, addò sarría leggibile da chiunque. Usala sulo da server a server.
  • Nun 'a mettere dint'ô codice sorgente e manco dint'a 'nu repository: usa 'na variabile d'ambiente o 'nu archivio 'e segreti.
  • Usa 'na chiave pe' ogni sistema cullegato (sito, gestionale, script 'e allineamento): accussì puo' revocarne una senza stutà 'e ate.
  • Se suspetti ca sia stata esposta, revocala sùbbeto d' 'o pannello: 'a revoca è immediata e nun è maje bloccata d' 'o stato dell'abbonamento. Da chillu mumento ogni chiamata cu' chella chiave riceve 401 invalid_key.
  • Traffico sulo 'ncopp'a HTTPS; 'o campo «urdemo utilizzo» dint'ô pannello t'aiuta a t'accorgere 'e usi inattesi.

4. Base URL

https://www.volleyfriends.com/api

'E path ducumentati cca sotto vanno accudati 'a base. 'O prefisso /api appartiene ô reverse proxy, quinni l'indirizzo completo 'e 'nu endpoint è pe' esempio:

GET https://www.volleyfriends.com/api/manager-api/v1/availability

Tutte 'e risposte so' application/json cu' codifica UTF-8. 'E richieste cu' corpo (POST, PATCH) hanno da avé Content-Type: application/json.

5. Rate limiting

'O limite è 'e 120 richieste ô minuto pe' chiave API (fenesta scorrevole 'e 1 minuto). 'O cunto è pe' chiave, no pe' ndirizzo IP: 'e gestionali stanno spisso areto ô stesso ndirizzo d' 'o provider e 'nu limite pe' IP penalizzasse gestore diverse ospitate 'ncopp'â stessa nfrastruttura. Se l'header X-Api-Key manca d' 'o tutto, 'o cunto cade 'ncopp'ô ndirizzo IP.

Ogni rispuosta riporta 'o stato d' 'o cuntatore dint'e header x-ratelimit-limit, x-ratelimit-remaining e x-ratelimit-reset (seconne ô reset). Quanno se supera, se mmette pure retry-after.

Rispuosta ô superamento — 429

{
  "error": "rate_limited",
  "message": "Limite di 120 richieste al minuto superato per questa chiave API."
}
Comme restà dint'ô limite
  • Pe' l'allineamento periodico ausa una sola chiamata a /bookings cu 'nu ntervallo fromto lario, nvece 'e 'na chiamata ô juorno.
  • Metti 'n cache l'alenco 'e strutture e campe: cagna raramente.
  • Dint'ô caso 'e 429 aspetta e pruova n'ata vota cu backoff esponenziale (pe' essempio 2, 4, 8 seconne), rispettanno retry-after.

6. Endpoint

Sije endpoint, tutte sotto /manager-api/v1. Ogni chiamata passa p' 'a stessa catena 'e cuntrolle, dint'a l'ordine: chiave API valida → funzione «API per gestionali esterni» nclusa dint'ô chiano → rate limit → validazione d' 'e parametre → verfeca ca 'a risorsa è 'a toja.

6.1 Strutture e campe

GET/api/manager-api/v1/venues

Elenca 'e strutture toje, ognuna cu 'e campe suoje annidate. È 'a chiamata da addò partì: l'id d' 'e campe (courtId) servono a tutte l'ate endpoint. 'E strutture stanno ordinate pe' nomme, 'e campe pe' nomme.

Parametre

Nisciuno.

Essempio 'e richiesta

curl -s https://www.volleyfriends.com/api/manager-api/v1/venues   -H "X-Api-Key: $VF_API_KEY"

Essempio 'e rispuosta — 200

{
  "venues": [
    {
      "id": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
      "name": "Centro Sportivo Aurora",
      "city": "Verona",
      "address": "Via delle Palestre 12",
      "verified": true,
      "courts": [
        {
          "id": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
          "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
          "name": "Campo 1",
          "surface": "parquet",
          "indoor": true,
          "lighting": true
        },
        {
          "id": "e2a71f64-9c03-4bd8-b512-38f6cd90a7e1",
          "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
          "name": "Campo 2 beach",
          "surface": "sabbia",
          "indoor": false,
          "lighting": true
        }
      ]
    }
  ]
}

Campe d' 'a rispuosta

CampoTipoDescrizione
venues[].iduuidIdentificativo d' 'a struttura (venueId dint'a l'ate endpoint).
venues[].namestringNomme d' 'a struttura.
venues[].citystring | nullCità.
venues[].addressstring | nullIndirizzo.
venues[].verifiedbooleantrue si 'a struttura tene 'o badge VERIFICATO.
venues[].courts[]arrayCampi d' 'a struttura. Array vacante si nun ne tene.
courts[].iduuidIdentificativo d' 'o campo (courtId dint'a l'ati endpoint).
courts[].venueIduuidStruttura a cui appartiene 'o campo.
courts[].namestringNomme d' 'o campo.
courts[].surfacestring | nullSuperficie, testo libero nzerito d' 'o gestore.
courts[].indoorbooleanCampo a 'o cupierto.
courts[].lightingbooleanIlluminazione disponibile.

Si l'account nun tene ancora strutture 'a rispuosta è {"venues": []}.

Errure specifiche

Nisciuno oltre a chille generali.

6.2 Elenco prenotaziune

GET/api/manager-api/v1/bookings

Restituisce 'e prenotaziune d' 'e strutture toe, ordinate pe' orario 'e inizio a crescere. L'elenco è paginato: a 'o massimo limit righe pe' chiamata (default 500, tetto 1000) — si riceve overamente limit righe, chiamma n'ata vota cu offset aumentato pe' 'a pagina appriesso. In produzione filtra comunque sempe ammeno pe' intervallo 'e date.

Parametri (query string)

NommeTipoObbl.Descrizione
venueIduuidnoLimita a una struttura. Si nun è 'a toja: 404 not_found.
courtIduuidnoLimita a nu campo. Se nun è 'o tujo: 404 not_found. Cumbinato cu nu venueId 'e n'ata struttura toja 'o risultato è n'elenco vacante.
fromdata o istante ISOnoEstremo 'nferiore 'ncluso. Na data secca AAAA-MM-GG vale 'a mezanotte locale taliana 'e chillu juorno.
todata o istante ISOnoEstremo superiore escluso. Na data secca vale 'a mezanotte locale d''o juorno appriesso: to=2026-08-31 'nclude tutto 'o 31 'e aùsto.
limitinteger 1–1000noNumero massimo 'e righe (default 500).
offsetinteger ≥ 0noRighe da zumpà (default 0): offset=500 è 'a seconna paggena cu 'o limit 'e default.
'Ncoppa a che agisce 'o filtro

from e to s'applicano a l'istante d'inizio d''a prenotazzione. Na prenotazzione accumminciata primma 'e from e ancora 'n corso doppo nun cumpare: se te serve, allarga l'estremo 'nferiore 'e quacche ora. 'O filtro nun esclude 'e prenotazzione annullate: l'elenco tene pure chelle cu status: "cancelled".

Essempio 'e richiesta

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/bookings   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"   --data-urlencode "from=2026-08-01"   --data-urlencode "to=2026-08-31"

Essempio 'e rispuosta — 200

{
  "bookings": [
    {
      "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
      "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
      "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
      "courtName": "Campo 1",
      "startsAt": "2026-08-12T16:00:00.000Z",
      "endsAt": "2026-08-12T17:30:00.000Z",
      "customerName": "Marta Bellini",
      "customerPhone": "+39 340 1122334",
      "customerEmail": "marta.bellini@example.com",
      "priceCents": 3000,
      "playersCount": null,
      "status": "confirmed",
      "paymentMethod": null,
      "paymentLink": null,
      "notes": "Prenotato dal sito della struttura",
      "source": "api",
      "recurrenceId": null,
      "createdAt": "2026-07-28T09:14:02.517Z",
      "updatedAt": "2026-07-28T09:14:02.517Z"
    }
  ],
  "limit": 500,
  "offset": 0
}

Campi 'e na prenotazzione

'A stessa struttura vene turnata da POST e PATCH (dinto a 'a chiave booking).

CampoTipoDescrizione
iduuidIdentificativo d''a prenotazzione.
venueIduuidStruttura.
courtIduuidCampo prenotato.
courtNamestringNomme d''o campo, pe' comodità 'e visualizzazzione.
startsAtistante ISOInizio, sempe in UTC (suffisso Z).
endsAtistante ISOFine, estremo escluso.
customerNamestringNomme d''o cliente.
customerPhonestring | nullTelefono.
customerEmailstring | nullEmail.
priceCentsinteger | nullPrezzo cuncurdato in centesime. null = da definire (maje 0 pe' «nun definito»).
playersCountinteger | nullNumero 'e persone dichiarato (sulo prenotaziune 'ncoppa a fasce cu prezzo a persona). null = nun applicabile o nun innicato.
statusstringpending · confirmed · paid · cancelled — vide stati.
paymentMethodstring | nullcash · bank_transfer · paypal · stripe · other. null = nun 'ncassato.
paymentLinkstring | nullLink 'e pavamento cu carta generato d''o pannello, se ce sta. Sulo in lettura.
notesstring | nullNote libbere.
sourcestringOriggene: manual (pannello) · api (sti API) · app (richiesta 'e 'nu jucatore d''a app) · tournament (turneo).
recurrenceIduuid | nullPresente e uguale 'ncoppa a tutte 'e ricurrenze 'e 'na serie ricurrente criata d''o pannello.
createdAtistante ISOCriazione.
updatedAtistante ISOUrdema modifica.

Errure specifiche

CodiceerrorQuanno
400invalid_inputvenueId/courtId nun so' UUID, o pure from/to nun so' date ca se ponno 'nterpretà.
404not_found'A struttura ("Struttura non trovata") o 'o campo ("Campo non trovato") nun esiste o nun è 'o tujo.

6.3 Nova prenotazione

POST/api/manager-api/v1/bookings

Cria 'na prenotazione 'ncoppa a 'nu campo tujo. 'A prenotazione nasce cu source: "api", accussì dint'ô pannello se distingue da chelle mise a mano, e 'o gestore riceve 'na notifica push «Nova prenotazione» 'ncoppa a l'app.

Veneno applicate 'e stesse regole d''o pannello, dint'a l'ordine:

  1. chiusura straordinaria d''a struttura dint'a data d'inizio → 409 venue_closed;
  2. sovrapposizione cu n'ata prenotazione nun annullata d''o stesso campo → 409 overlap;
  3. prezzo assente → calcolato d''o listino d''o campo (null se l'orario d'inizio nun cade dint'a nisciuna fascia). Se 'a fascia tene 'o prezzo a persona, serve pure playersCount: senza, 'a richiesta vene rifiutata cu 400 players_required (a meno ca nun se mposta 'nu priceCents esplicito).

'E orari d'apertura nun bloccano 'a criazione: so' 'nformativi, 'o gestore resta sovrano 'ncoppa ô campo d''o suoio. Se vuo' 'mpedì prenotaziune fore orario, controlla tu hours turnato da /availability primma 'e chiammà 'a POST.

Cuorpo d''a richiesta (JSON)

NommeTipoObbl.Descrizione
courtIduuidCampo da prenotà. Adda appartené a 'na struttura toja.
startsAtistante ISO 8601 cu offsetInizio. Songo accettate sia 'a forma 2026-08-12T18:00:00Z sia 2026-08-12T18:00:00+02:00. Senza offset: 400.
endsAtistante ISO 8601 cu offsetFine, adda essere successiva a startsAt.
customerNamestring (1–160)Nomme d''o cliente.
customerPhonestring (max 40)noTelefono.
customerEmailemail (max 200)noEmail, validata comme indirizzo.
priceCentsinteger ≥ 0noPrezzo 'n centesime. Se omesso vene calcolato d''o listino d''o campo. Inneca 0 sulo pe' 'na prenotazione overamente gratis.
playersCountinteger 1–500noQuante persone. Richiesto se 'o prezzo s'adda calcolà d''o listino e 'a fascia d''o orario d'inizio è a persona; 'o totale applica l'eventuale minimo garantito d''a fascia.
notesstring (max 2000)noNote libbere, visibbile a 'o gestore dint'a 'o pannello.
statuspending | confirmed | paid | cancellednoDefault confirmed. Da 'nu gestionale esterno usa confirmed o paid: pending è riservato a 'e richieste ca arrivano d''all'app d''e jucature (vedi stati).
paymentMethodcash | bank_transfer | paypal | stripe | othernoComme è stato (o sarrà) incassato. Omesso = nun incassato.
recurrenceobjectnoNun supportato da cheste API: se ce sta, 'a richiesta vene rifiutata cu 400 recurrence_unsupported (nisciuna prenotazione criata). 'E serie ricurrente restano 'na funzione d''o pannello: da 'nu gestionale esterno ripeti 'a POST pe' ogne occorrenza.

Essempio 'e richiesta

curl -s -X POST https://www.volleyfriends.com/api/manager-api/v1/bookings   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "startsAt": "2026-08-12T18:00:00+02:00",
    "endsAt": "2026-08-12T19:30:00+02:00",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "notes": "Prenotato dal sito della struttura"
  }'

Esempio 'e risposta — 201

{
  "booking": {
    "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
    "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "courtName": "Campo 1",
    "startsAt": "2026-08-12T16:00:00.000Z",
    "endsAt": "2026-08-12T17:30:00.000Z",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "priceCents": 3000,
    "playersCount": null,
    "status": "confirmed",
    "paymentMethod": null,
    "paymentLink": null,
    "notes": "Prenotato dal sito della struttura",
    "source": "api",
    "recurrenceId": null,
    "createdAt": "2026-07-28T09:14:02.517Z",
    "updatedAt": "2026-07-28T09:14:02.517Z"
  }
}

Dint'a l'esempio priceCents nun era stato innecato: 90 minute 'ncoppa a 'na fascia da 20,00 €/ora danno 3000 centesime ('o calcolo è proporzionale a 'e minute effettive, cu 'a tariffa d''a fascia addò accummincia 'a prenotazione).

Errure specifiche

CodiceerrorQuanno
400invalid_inputCuorpo nun valido: campo obbligatorio ca manca, istante senza offset, endsAt ca nun vene doppo startsAt, email nun valida, lunghezze fore limite.
400players_requiredPrezzo da calcolà d''o listino 'ncoppa a 'na fascia a persona, ma playersCount assente.
400recurrence_unsupported'O cuorpo tene recurrence: 'e ricorrenze nun songo disponibbile da cheste API.
403subscription_requiredNisciuno abbonamento gestore in corso.
404not_found"Campo non trovato" — 'o courtId nun esiste o nun è 'o tujo.
409venue_closed'A struttura tene 'na chiusura straordinaria dint'â data 'e inizio.
409overlap'O campo tene già 'na prenotazione nun annullata ca se sovrappone a l'intervallo.
// 409 — sovrapposizione
{ "error": "overlap", "message": "Il campo è già prenotato in quell'orario." }

// 409 — chiusura straordinaria ('o mutivo, se nnicato d' 'o gestore, sta dint'ô messaggio)
{ "error": "venue_closed", "message": "Struttura chiusa in quella data (manutenzione)." }
Idempotenza

Nun esiste 'na chiave 'e idempotenza: repetere 'a stessa POST doppo 'nu timeout può crià 'nu duplicato o, cchiù spisso, turnà 409 overlap pecché 'o primmo tentativo era gghiuto a buon fine. Dint'a 'nu caso 'e rispuosta ncerta, primma 'e turnà a pruvà verifeca cu GET /bookings ncopp'a l'intervallo nteressato.

6.4 Cagna prenotazione

PATCH/api/manager-api/v1/bookings/{id}

Aggiurna 'na prenotazione ca già ce sta. È n'aggiurnamento parziale: manna sulo 'e campe ca cagnano, l'ate restano tale e quale. 'O cuorpo adda tené almanco 'nu campo.

Nun esiste n'endpoint 'e cancellazione: pe' annullà 'na prenotazione s'addorza status: "cancelled". 'O storeco resta dint'ô pannello e 'o slot turna libbero ('e prenotazzione annullate nun occupano 'o campo e nun generano overlap).

Parametro 'e percorso

NommeTipoObbl.Descrizione
iduuidId d' 'a prenotazione, da GET /bookings o d' 'a rispuosta d' 'a POST.

Cuorpo d''a richiesta (JSON)

Tutti 'e campe so' opzionali. Chille marcate «annullabile» accettano null pe' svutà 'o valore.

NommeTipoNote
courtIduuidSposta 'a prenotazione ncopp'a n'ato campo tujo, pure 'e n'ata struttura toja (venueId vene aggiurnato 'e conseguenza).
startsAtistante ISO cu offsetNuovo inizio.
endsAtistante ISO cu offsetNuova fine. 'O resultato finale adda restà successivo a l'inizio, pure cumbinando sulo n'estremo cu 'o valore già sarvato.
customerNamestring (1–160)
customerPhonestring (max 40)Annullabile.
customerEmailemail (max 200)Annullabile.
priceCentsinteger ≥ 0Annullabile (null = prezzo 'a definì). Dint'a PATCH 'o prezzo nun vene ricalcolato d' 'o listino: se sposte l'orario e vuo' 'o prezzo nuovo, addòralo tu.
playersCountinteger 1–500Annullabile. Aggiurna sulo 'o dato: 'o prezzo nun vene ricalcolato d'ufficio — se 'o nummero 'e persone cagna 'o totale, manna pure 'o nuovo priceCents.
notesstring (max 2000)Annullabile.
statuspending | confirmed | paid | cancelledQualsiasi transizione è ammessa. È pure 'o modo 'e rispunnere a 'na richiesta arrivata d' 'a app (status: "pending" cu source: "app"): puortala a confirmed pe' l'accettà o a cancelled pe' 'a rifiutà — 'o jucatore riceve 'a notifica.
paymentMethodcash | bank_transfer | paypal | stripe | otherAnnullabile.
Quanno veneno ricuntrollate 'e cunflitte

'E cuntrolle 'e chiusura e sovrapposizione se fanno n'ata vota dint'a duje casi: quanno 'a richiesta sposta 'o slot (startsAt, endsAt o courtId) e quanno riattiva 'na prenotazione annullata (status da cancelled a qualsiasi ato stato) — da annullata nun occupava 'o campo, e intanto 'o slot putesse essere stato pigliato: in chillo caso 'a PATCH risponne 409 overlap o 409 venue_closed. 'Na PATCH ca cagna sulo ate campe (prezzo, note, incasso) nun 'e ripete.

Esempio 'e richiesta — spostamento e incasso

curl -s -X PATCH   https://www.volleyfriends.com/api/manager-api/v1/bookings/9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{
    "startsAt": "2026-08-12T19:00:00+02:00",
    "endsAt": "2026-08-12T20:30:00+02:00",
    "status": "paid",
    "paymentMethod": "cash",
    "priceCents": 3000
  }'

Esempio 'e richiesta — annullamento

curl -s -X PATCH   https://www.volleyfriends.com/api/manager-api/v1/bookings/9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f   -H "X-Api-Key: $VF_API_KEY"   -H "Content-Type: application/json"   -d '{ "status": "cancelled" }'

Essempio 'e rispuosta — 200

'A prenotazione aggiurnata, dint'ô stesso formato d' 'a POST:

{
  "booking": {
    "id": "9d51c7b4-0e28-4f3a-a6d9-72b48e105c3f",
    "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
    "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
    "courtName": "Campo 1",
    "startsAt": "2026-08-12T17:00:00.000Z",
    "endsAt": "2026-08-12T18:30:00.000Z",
    "customerName": "Marta Bellini",
    "customerPhone": "+39 340 1122334",
    "customerEmail": "marta.bellini@example.com",
    "priceCents": 3000,
    "playersCount": null,
    "status": "paid",
    "paymentMethod": "cash",
    "paymentLink": null,
    "notes": "Prenotato dal sito della struttura",
    "source": "api",
    "recurrenceId": null,
    "createdAt": "2026-07-28T09:14:02.517Z",
    "updatedAt": "2026-07-28T11:02:47.883Z"
  }
}

Errure specifiche

CodiceerrorQuanno
400invalid_inputCuorpo vuoto ("Nessun campo da aggiornare"), valore nun valide, o pure orario 'e fine nun successivo a chillo d'inizio ("L'orario di fine deve essere successivo a quello di inizio").
403subscription_requiredNisciuno abbonamento gestore in corso.
404not_found"Prenotazione non trovata" o pure "Campo non trovato" se 'o nuovo courtId nun è 'o tujo.
409venue_closedSpostamento dint'a 'na data 'e chiusura straordinaria.
409overlap'O nuovo orario se sovrappone a n'ata prenotazione nun annullata d' 'o stesso campo.

6.5 Disponibilità 'e 'nu campo dint'a 'nu juorno

GET/api/manager-api/v1/availability

Restituisce, pe' 'nu campo e 'nu juorno, 'e slot occupati, 'e orari 'e apertura 'e chillo juorno d' 'a settimana e l'eventuale chiusura straordinaria. È l'endpoint da ausà pe' calcolà 'e slot libbere 'ncopp'a 'nu sito esterno senza duplicà 'e regole d' 'o gestionale: sottrai 'e prenotazione d' 'a finestra 'e apertura.

Ce stanno elencate tutte 'e slot ca occupano 'o campo, in qualunque stato tranne cancelled: quinn' pure 'e richieste 'e prenotazione online ancora pending. 'O juorno è chillo locale italiano e l'intervalli so' semiaperte: 'na prenotazione ca fernisce esattamente a mezanotte appartene ô juorno primma. 'Na prenotazione a cavallo d' 'a mezanotte compare dint'a tutt'e duje 'e juorne ca interseca, cu 'e mumente riale d' 'e suoje (ca ponno cadé fore d' 'o juorno richiesto).

Parametri (query string)

NommeTipoObbl.Descrizione
courtIduuidCampo addò s'ha da legge 'a disponibilità. Adda essere 'o tujo.
dateAAAA-MM-GGJuorno locale italiano. Formato diverso: 400 cu 'o messaggio "Data non valida (AAAA-MM-GG)".

Essempio 'e richiesta

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/availability   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"   --data-urlencode "date=2026-08-12"

Essempio 'e rispuosta — 200

{
  "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
  "venueId": "b3f8e5c1-2d47-4a90-8f31-6c0d9a7e4512",
  "date": "2026-08-12",
  "timezone": "Europe/Rome",
  "hours": {
    "weekday": 2,
    "openMinute": 540,
    "closeMinute": 1380,
    "closed": false,
    "configured": true
  },
  "closure": null,
  "bookings": [
    {
      "startsAt": "2026-08-12T16:00:00.000Z",
      "endsAt": "2026-08-12T17:30:00.000Z",
      "status": "confirmed"
    },
    {
      "startsAt": "2026-08-12T18:00:00.000Z",
      "endsAt": "2026-08-12T19:00:00.000Z",
      "status": "paid"
    },
    {
      "startsAt": "2026-08-12T19:00:00.000Z",
      "endsAt": "2026-08-12T20:30:00.000Z",
      "status": "pending"
    }
  ]
}

Campe d' 'a rispuosta

CampoTipoDescrizione
courtIduuidCampo richiesto.
venueIduuidStruttura d' 'o campo.
dateAAAA-MM-GGJuorno richiesto, ripetuto.
timezonestringSempe "Europe/Rome": 'o fuso addò s'hanno da interpretà date e 'e minute d' 'e orari.
hours.weekdayinteger 0–6Juorno d' 'a settimana: 0 = lunedì … 6 = dummeneca.
hours.openMinuteinteger | nullApertura in minute d' 'a mezanotte locale (540 = 09:00). null se 'o juorno è dichiarato chiuso.
hours.closeMinuteinteger | nullChiusura in minute (1380 = 23:00). null se 'o juorno è dichiarato chiuso.
hours.closedbooleantrue se 'o gestore ha dichiarato chillo juorno d' 'a settimana comme chiuso.
hours.configuredbooleanfalse quanno 'o gestore nun ha impostato l'orari pe' chillo juorno: in chillo caso openMinute/closeMinute valgono 'a convenzione predefinita 480 (08:00) – 1380 (23:00), ca è 'nu ripiego 'e visualizzazione, nun 'nu orario dichiarato.
closureobject | nullChiusura straordinaria attiva dint'ô juorno richiesto, oppuro null.
closure.fromAAAA-MM-GGPrimmo juorno 'e chiusura.
closure.toAAAA-MM-GGUltemo juorno 'e chiusura, ncluso.
closure.reasonstring | nullMutivo, se nnicato d' 'o gestore.
bookings[]arraySlot occupate, urdenate pe' nizio. Solo startsAt, endsAt e status (pending, confirmed o paid): nisciuno dato d' 'o cliente, accussì 'a rispuosta se pô ausà pe' custruì 'nu calannario pubblico.
Cu 'na chiusura 'n corso

Quanno closure nun è null 'o juorno è d' 'a cunziderà nun prenotabbele, a prescindere da hours: 'na POST dint'a chella data riceverria 409 venue_closed.

Errure specifiche

CodiceerrorQuanno
400invalid_inputcourtId mancante o nun UUID, date mancante o nun dint'ô formato AAAA-MM-GG.
404not_found"Campo non trovato" — 'o campo nun esiste o nun è 'o tujo.

6.6 Listino 'e 'nu campo

GET/api/manager-api/v1/rates

'O listino d' 'o campo in sola lettura: serve a mustrà 'e prezze a 'o cliente primma d' 'a prenotazzione, cu 'e stesse fasce ca 'o gestionale ausa pe' calculà 'o prezzo automatico. 'E fasce se modificano sulo d' 'o pannello. Songo urdenate pe' fromMinute crescente.

Parametri (query string)

NommeTipoObbl.Descrizione
courtIduuidCampo d' 'o quale s'ha da leggere 'o listino. Adda essere 'o tujo.

Essempio 'e richiesta

curl -s -G https://www.volleyfriends.com/api/manager-api/v1/rates   -H "X-Api-Key: $VF_API_KEY"   --data-urlencode "courtId=7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05"

Essempio 'e rispuosta — 200

{
  "courtId": "7c94a0d2-58b1-4e6f-9a3c-1d20f8b47e05",
  "rates": [
    {
      "id": "4a1e0b72-6d35-4c81-93af-0b7e2d5814c6",
      "label": "Mattina infrasettimanale",
      "daysMask": 31,
      "fromMinute": 480,
      "toMinute": 840,
      "pricePerHourCents": 1500,
      "pricingMode": "court",
      "minPlayers": null
    },
    {
      "id": "c07d9b31-8f42-4a05-b6e9-15d3c8017a2b",
      "label": "Serale",
      "daysMask": 127,
      "fromMinute": 1080,
      "toMinute": 1380,
      "pricePerHourCents": 600,
      "pricingMode": "person",
      "minPlayers": 10
    }
  ]
}

Campe d' 'a rispuosta

CampoTipoDescrizione
courtIduuidCampo richiesto.
rates[].iduuidIdentificativo d' 'a fascia.
rates[].labelstringEtichetta scigliuta d' 'o gestore (es. «Serale»).
rates[].daysMaskinteger 1–127Bitmask d' 'e juorne: lun 1, mar 2, mer 4, gio 8, ven 16, sab 32, dom 64. 127 = tutte 'e juorne, 31 = da lunnerì a vennerì.
rates[].fromMinuteinteger 0–1440Inizio d' 'a fascia in minute d' 'a mezanotte locale.
rates[].toMinuteinteger 0–1440Fine d' 'a fascia, sempe maggiore 'e fromMinute.
rates[].pricePerHourCentsinteger > 0Prezzo orario in centeseme (2000 = 20,00 €). Cu pricingMode: "person" è 'o prezzo orario a persona (600 = 6,00 €/persona all'ora).
rates[].pricingModecourt | personcourt = prezzo d' 'o campo (default). person = prezzo a persona: 'o totale scala cu 'o nummero 'e persone, maje a 'o ribasso.
rates[].minPlayersinteger | nullMinimo garantito d''a fascia a persona: sotto a chillu nummero se pava comunque p''o minimo. null = nisciuno minimo.
Comme vene calculato 'o prezzo 'e 'na prenotazzione

Se guarda l'istante 'e inizio: 'mmiez'ê fasce d''o campo se piglia 'a prima (in ordine 'e fromMinute) addò 'o juorno è attivo dint'â bitmask e ca cuntene 'o minuto 'e inizio (fromMinute ≤ inizio < toMinute). 'O prezzo è proporzionale ê minute effettivi: arrotonda(pricePerHourCents × minuti / 60) — 90 minute a 20,00 €/ora fanno 30,00 €. 'Na prenotazzione a cavallo 'e ddoje fasce resta valorizzata cu 'a tariffa d''a fascia 'e inizio. Nisciuna fascia currispunnente: priceCents risulta null (prezzo a definì), maje 0.

Cu 'na fascia a persona (pricingMode: "person") 'o resultato orario se murtipleca p''e persone fatturate: max(playersCount, minPlayers). Esempio cu 'a fascia d''a sera cca 'ncoppa (6,00 €/persona all'ora, minimo 10): 60 minute cu 12 persone → 72,00 €; cu 16 → 96,00 € ('o prezzo a persona nun cala); cu 8 → 60,00 € (scatta 'o minimo garantito). Senza playersCount 'o prezzo nun se pô calculà: null in lettura, 400 players_required dint'â POST ca se fida d''o listino.

Errure specifiche

CodiceerrorQuanno
400invalid_inputcourtId ca manca o nun è UUID.
404not_found"Campo non trovato" — 'o campo nun esiste o nun è 'o tujo.

'Nu campo senza listino risponne 200 cu "rates": [].

7. Cunvenziune d''e date

7.1 Date e orare

  • In ingresso l'istante songo stringhe ISO 8601 cu offset obbricatorio: 2026-08-12T18:00:00+02:00 oppure 2026-08-12T18:00:00Z. 'Na stringa senza offset (2026-08-12T18:00:00) vene refutata cu 400: sarrìa ambigua, e pe' 'nu calannario è 'n'ambiguità ca se pava cu prenotazzione sbagliate 'e n'ora.
  • In uscita l'istante songo sempe nurmalizzate in UTC cu suffisso Z e milliseconne: "2026-08-12T16:00:00.000Z". Cunvertile dint'ô fuso lucale primma 'e amustrà.
  • 'E date sicche (date, closure.from, closure.to, e from/to quanno l'use a forma 'e juorno) songo AAAA-MM-GG e se referiscono ô juorno lucale taliano.
  • L'intervalle songo semiaperte [inizio, fine): 18:00–19:00 e 19:00–20:00 nun stanno in cunflitto.

7.2 Fuso orario

'E prenotazzione songo cunservate comme istante assolute, ma tutte 'e regule 'e calannario — juorno d''a semmana, fasce d''o listino, orare 'e apertura, date 'e chiusura, cunfine d''o juorno — songo valutate dint'ô fuso Europe/Rome, cu l'ora legale gestita automaticamende. 'O campo timezone d''a rispuosta 'e /availability 'o dichiara esplicitamende. Se 'o server tujo gira in UTC o dint'a n'ato fuso, nun cunvertì a mano 'e minute: songo ggià espresse in ora lucale taliana.

7.3 Minute d''a mezanotte

L'orare «da calannario» (openMinute, closeMinute, fromMinute, toMinute) songo nummere 'ntere da 0 a 1440 ca cuntano 'e minute d''a mezanotte lucale. Cunversione: ore = ⌊m / 60⌋, minuti = m mod 60.

MinuteOra lucaleMinuteOra lucale
000:00108018:00
48008:00132022:00
54009:00138023:00
84014:00144024:00 (fine d''a jurnata)

7.4 Importe

Tutte l'importe songo nummere 'ntere in centesime 'e euro (priceCents, pricePerHourCents): nisciuno valore cu 'a virgula, nisciuno simmolo 'e valuta. 2000 = 20,00 €. 'Ncoppa a 'na prenotazzione, priceCents: null significa «prezzo a definì» ed è deverzo da 0, ca significa «gratis».

7.5 State 'e 'na prenotazzione

StatoSignificatoOccupa 'o slot?
pendingRichiesta 'e prenotazzione online 'n attesa d' 'a decisione d' 'o gestore. Nasce sulo d' 'e richieste mannate d' 'e jucature d' 'all'app VolleyFriends (source: "app"): 'o gestore 'a accetta (confirmed) o 'a rifiuta (cancelled). — 'o slot è già bloccato, pe' evità doppie richieste 'ncopp'ô stesso orario
confirmedPrenotazione valida, nun ancora incassata. È 'o stato iniziale 'e ogne prenotazione creata da chest'API e d''o pannello.
paidPrenotazione valida e incassata. 'E norma accumpagnata da paymentMethod.
cancelledPrenotazione annullata (o richiesta rifiutata). Resta dint'ô storico ma libera 'o campo: nun genera overlap e nun comparisce dinto a /availability.No
Comme trattà 'e prenotazzione «pending»
  • 'E truove dinto a GET /bookings e dint'e slot occupate 'e /availability: tratta 'o slot comme nun disponibile, tale e quale a 'na confirmed.
  • Puo' risponnere a 'a richiesta d''o gestionale tujo cu 'na PATCH: {"status": "confirmed"} pe' l'accettà, {"status": "cancelled"} pe' 'a rifiutà. 'O jucatore riceve 'na notifica cu l'esito.
  • Ricanuscile d''a coppia status: "pending" + source: "app". 'E date d''o cliente arrivano d''o profilo VolleyFriends d''o jucatore (nomme ed email), quinni customerPhone pò essere null.
  • Nun crià prenotazzione pending da chest'API: 'o valore è accettato d''a validazione, ma chillo stato descrive 'na richiesta 'n attesa 'e risposta da parte d''o gestore e nisciuno 'a decidarria d''o lato tujo. Se dint'ô flusso tujo ce sta 'nu carrello o 'nu pavamento da completà, tiene l'attesa dint'ô sistema tujo e chiamma 'a POST quanno 'a prenotazione è definitiva — o si no criala confirmed e portala a cancelled se 'o pavamento nun arriva.

7.6 Origgine e metodo 'e pavamento

CampoValureSignificato
sourcemanualInserita d''o gestore dint'ô pannello.
apiCreata da 'nu gestionale esterno cu chest'API. Valore sempe 'mpustato d''a POST, nun modificabile.
appRichiesta 'e prenotazione online mannata da 'nu jucatore d''all'app VolleyFriends: nasce pending e aspetta 'a decisione toja.
tournamentGenerata d''all'organizzazione 'e 'nu torneo 'ncopp'e campe d''a struttura.
paymentMethodcash, bank_transfer, paypal, stripe, otherComme è stato incassato. null = nun incassato.

Tutt'e duje songo domini testuali: nuove valure ponno essere aggiunte 'n futuro senza cagnà versione, quinni 'o codice tujo nun adda jì 'n errore 'ncopp'a 'nu valore ca nun canosce.

7.7 Date personale d''e cliente

Nomme, telefono ed email ca manne dint'e prenotazzione songo date personale d''e cliente tuoje: si' tu 'o titolare d''o trattamento, VolleyFriends 'e cunserva pe' cunto tujo comme responsabile ai sensi dell'art. 28 GDPR. Manna sulo chello ca serve a 'a gestione d''o campo e informa 'e cliente tuoje. 'O dettaglio sta dint'a privacy policy.

8. Errore generale

Ogni errore tene 'o stesso cuorpo: 'nu codice stabile dint'a error, pensato p' 'o codice tujo, e 'nu message in italiano, pensato p' 'e ggenti. Piglia 'e decisioni toje 'ncopp'a error e 'ncopp'ô stato HTTP, no 'ncopp'ô testo d' 'o messaggio, ca pô cagnà.

{
  "error": "overlap",
  "message": "Il campo è già prenotato in quell'orario."
}

'E ll'errore 'e validazione azzongono issues, 'a lista dettagliata d' 'e prubleme campo pe' campo:

{
  "error": "invalid_input",
  "message": "Dati non validi",
  "issues": [
    {
      "code": "invalid_string",
      "validation": "datetime",
      "path": ["startsAt"],
      "message": "Invalid datetime"
    }
  ]
}
HTTPerrorSignificatoChe s'ha da fà
400invalid_inputParametre o cuorpo nun valide. 'O dettaglio sta dint'a issues.Acconcia 'a richiesta. Nun ce pruvà n'ata vota tale e quale: 'o resultato nun cagna.
401invalid_keyHeader X-Api-Key assente, malformato, scanusciuto o revocato.Verifica 'e mannà l'header e ca 'a chiave sia attiva dint'ô pannello. Si è stata revocata, generane una nova.
403subscription_requiredNisciuno abbonamento «Gestore campi» in corso 'ncopp'all'account proprietario d' 'a chiave.Riattiva l'abbonamento dall'app (Profilo → area gestore → Abbonamento). Nisciuna chiamata funziona nfino a chillu mumento.
403feature_not_includedAbbonamento attivo, ma 'o piano nun cumprende «API per gestionali esterni». 'O messaggio nomina 'o piano in corso.Passa a 'nu piano ca cumprende 'a funzione. Vale pe' tutta 'a v1, letture ncluse.
404not_foundRisorsa ca nun esiste oppure ca appartene a n'ato gestore: 'e ddoje situazzione nun se spartono, pe' nun fà vedé 'e ddati 'e ll'ati ggenti.Ligge n'ata vota 'e id da /venues e da /bookings: quase sempe è 'nu id viecchio o cupiato da n'ato account.
409overlap'O campo è già occupato dint'all'intervallo richiesto da 'na prenotazzione nun scancellata.Pruponi n'ato slot: ligge n'ata vota /availability. Nun ce pruvà n'ata vota senza cagnà orario.
409venue_closedChiusura straordinaria d' 'a struttura dint'a data richiesta.Pruponi n'ata data. 'E chiusure se leggono da /availability (closure).
429rate_limitedSuperate 'e 120 richieste ô minuto p' 'a chiave.Aspetta e pruvace n'ata vota cu backoff esponenziale, rispettanno retry-after.
4xxerrorCodice generico pe' ll'errore 'e richiesta ca nun cadono dint'ê casi 'e coppa (raro).Ligge message e acconcia 'a richiesta.
500internalErrore ca nun s'aspettava d' 'a parte nosta.Pruove n'ata vota cchiù tardi. Si cuntinua, scrivice specificanno l'ora, l'endpoint e 'o prefisso d' 'a chiave (nun 'a chiave).

'Nu path ca nun esiste sotto 'a base risponne 404; 'a stessa cosa vale pe' 'nu metodo ca nun è previsto 'ncoppa a 'nu path ca esiste:

{
  "error": "not_found",
  "message": "Risorsa non trovata"
}

'E risposte 502, 503 e 504 arrivano d' 'o reverse proxy quanno l'API nun se pò raggiongere (riavvio o manutenzione): dint'a chillu caso 'o cuorpo nun è garantito in formato JSON. Trattale comme a errore temporanee e pruove n'ata vota cu 'o backoff, senza pruvà a sutterrà 'o cuntenuto.

9. Versioni e compatibilità

'A versione sta dint' 'o path: /manager-api/v1. Nun ce stanno header 'e versione né date 'e release da specificà: l'unica versione ca sta mo' pubblicata è v1.

Che cosa possiamo cambiare senza avvisarti

  • Aggiungere campi alle risposte esistenti.
  • Aggiungere parametri opzionali alle richieste, con un valore predefinito che conserva il comportamento attuale.
  • Aggiungere nuovi endpoint sotto /v1.
  • Aggiungere valori ai campi testuali aperti (source, paymentMethod, surface).
  • Riformulare i message degli errori, mantenendo invariati i codici error.

Che cosa non cambia dentro la v1

  • Nessun campo verrà rimosso o rinominato dalle risposte.
  • Nessun campo cambierà tipo o significato.
  • Nessun parametro oggi opzionale diventerà obbligatorio.
  • I codici error e gli stati HTTP documentati qui restano quelli.

Qualunque modifica che rompa queste garanzie arriverà su un nuovo prefisso (/v2), con la v1 mantenuta in servizio e un preavviso ai gestori che la stanno usando.

Come scrivere un client che non si rompe
  • Ignora i campi che non conosci invece di andare in errore su di essi (nessun parsing «strict» che rifiuta le proprietà inattese).
  • Gestisci i valori sconosciuti dei campi testuali aperti con un ramo di ripiego.
  • Non fare affidamento sull'ordine delle chiavi JSON né sul testo dei messaggi.
  • Tratta null e campo assente come equivalenti in lettura.

Changelog

VersioneDataNote
v1lug 2026Aggiunte compatibbile: tariffe a persona dint'ô listino (pricingMode, minPlayers) e playersCount ncopp'ê prenotaziune (cu l'errore players_required); paginazzione limit/offset ncopp'â lista d'e prenotaziune; ricontrollo d'e cunflitte quanno se riattiva 'na prenotazzione annullata; recurrence mo rifiutato esplicitamente cu 400 recurrence_unsupported (primma s'ignorava senza dicere niente).
v12026Primma versione pubbleca: strutture e campe, prenotaziune (lista, criazzione, modifeca), disponibbelità d'a jurnata, listino. Autenticazzione cu X-Api-Key, 120 richieste/menuto pe' chiave.

10. Supporto a l'integrazzione

Pe' dumande tecniche, cumportamente ca nun t'aspette o richieste 'e endpoint ca nun truove ccà, scrivice d'a paggena Contatte. Pe' ghjì deritto ô punto, scrive dint'ô messaggio:

  • endpoint e metodo ca staje chiammanno;
  • data e ora d'a chiamata (cu 'o fuso) e 'o codice HTTP arricivuto;
  • codice error e messaggio d'a risposta;
  • prefisso d'a chiave ausata (es. vfk_9f2c).
Maje dint'ô messaggio

Nun ce mannà 'a chiave API cumpleta pe' nisciuno canale, manco pe' ce fà verifecà 'nu prebblema: 'o prefisso ce basta pe' ll'identifecà. Si ll'haje già spartuta cu coccheduno, revocala e generane 'na nova.

Si haje bisogno 'e pruvà l'integrazzione senza tuccà 'o calannario reale, crija 'na struttura 'e prova cu 'nu campo dedicato e ausa chella: tutte 'e chiammate so' limitate a 'e strutture d'o pruprietario d'a chiave, accussì 'o riesto d'o cunto tujo nun è cuinvolto.