API e webhook per sviluppatori
Collega il tuo sito, il tuo gestionale o le tue app al tuo account Yuppi. Chiavi API e webhook sono compresi nei piani Pro e Agency Suite, senza costi in più.
Contratto in fase di implementazione
Questa è la versione 1 dell’interfaccia, ancora in costruzione: indirizzi e campi possono cambiare prima dell’apertura. Ogni modifica sarà segnata in questa pagina.
Autenticazione
Crea una chiave dal Gestionale, in “Calendario, API e webhook”. Dai a ogni chiave un nome e solo i permessi che servono.
La chiave completa si vede una volta sola, quando la crei: la salviamo in modo che nemmeno noi possiamo rileggerla. Se la perdi, revocala e creane un’altra.
Mandala in ogni richiesta nell’intestazione Authorization. Usala solo dal tuo server: mai nel codice di una pagina web o di un’app che altri possono scaricare.
Authorization: Bearer yk_live_...| Permesso | Cosa permette |
|---|---|
| bookings:read | Leggere le prenotazioni |
| bookings:write | Confermare, rifiutare e aggiornare le prenotazioni |
| calendar:read | Leggere l’agenda, compresi gli impegni importati dal tuo calendario |
| clients:read | Leggere i clienti |
| quotes:read | Leggere i preventivi |
| services:read | Leggere i servizi |
Indirizzo e formati
https://yuppi.now/v1- Richieste e risposte sono in JSON (UTF-8), con nomi dei campi in camelCase.
- I giorni sono nel formato “YYYY-MM-DD”; gli istanti in ISO 8601 con fuso, per esempio “2026-10-10T14:00:00+02:00”.
- Gli importi sono in centesimi di euro, IVA inclusa: 28000 vuol dire 280,00 €.
- Le liste sono a pagine: ?page=1 e la risposta ha items, page, pageSize e total.
- Le scritture (POST) portano un’intestazione Idempotency-Key con un valore unico: se ripeti la stessa richiesta, non viene eseguita due volte.
curl "https://yuppi.now/v1/provider/bookings?status=pending&page=1" \
-H "Authorization: Bearer yk_live_..." \
-H "Accept: application/json"Errori
Gli errori seguono RFC 9457 (application/problem+json): lo stato HTTP, un code stabile da usare nel tuo codice e, per i dati non validi, errors con un messaggio per campo.
- 401
- chiave mancante, sbagliata o revocata
- 403
- insufficient_scope: la chiave non ha il permesso; addon_required: il piano non comprende gli strumenti
- 404
- non trovato, o non è del tuo account
- 409
- lo stato non lo permette, per esempio una prenotazione già confermata
- 422
- dati non validi
- 429
- troppe richieste: aspetta i secondi indicati in Retry-After
{
"type": "about:blank",
"title": "Forbidden",
"status": 403,
"detail": "La chiave non ha il permesso bookings:read.",
"code": "insufficient_scope",
"requestId": "req_7f3a9c2e"
}Endpoint principali
Leggono e scrivono solo i dati del tuo account. Gli esempi mostrano il formato delle risposte, con dati di prova.
GET
/provider/bookings?status=&page=Prenotazioni, dalla più recente; status: pending, confirmed, declined, cancelled, completed
Permesso:
bookings:readEsempio di risposta { "items": [ { "id": "bkg_m3x8q2", "code": "YU-7KQ2XH", "status": "confirmed", "service": { "id": "svc_4r9t1c", "title": "Festa di compleanno con il mago" }, "package": { "name": "Festa completa", "durationMinutes": 120, "maxChildren": 25 }, "date": "2026-10-17", "startTime": "16:00", "address": "Via Toledo 120", "town": "Napoli", "children": 18, "ageBand": "4-7", "notes": "Festa a tema pirati, torta alle 17:30", "customer": { "id": "cus_8h2k4d", "name": "Giulia Esposito", "email": "giulia@example.com", "phone": "+39 333 000 0000" }, "totalCents": 28000, "createdAt": "2026-09-20T10:12:00+02:00", "respondBy": "2026-09-21T10:12:00+02:00", "declineReason": null, "timeline": [ { "at": "2026-09-20T10:12:00+02:00", "type": "created", "by": "customer", "note": null }, { "at": "2026-09-20T11:03:00+02:00", "type": "confirmed", "by": "provider", "note": null } ], "assignees": [ { "id": "stf_2p7w9z", "name": "Marco Russo" } ], "entertainersNeeded": 1, "deposit": { "amountCents": 8400, "status": "paid", "paidAt": "2026-09-20T18:40:00+02:00" }, "balance": { "amountCents": 19600, "status": "due", "paidAt": null }, "dispute": null, "noShow": null, "canMarkNoShow": false, "canDispute": false } ], "page": 1, "pageSize": 20, "total": 1 }GET
/provider/bookings/{id}Una prenotazione, con storico e caparra
Permesso:
bookings:readPOST
/provider/bookings/{id}/confirmConferma una prenotazione in attesa
Permesso:
bookings:writeConfermare una prenotazione: depositPercent (10-50) chiede una caparra alla famiglia; le agenzie possono indicare assigneeIds, chi fa la festa.
Esempio di richiesta curl -X POST "https://yuppi.now/v1/provider/bookings/bkg_m3x8q2/confirm" \ -H "Authorization: Bearer yk_live_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 4f1c2a9e-8d3b-4f6a-9c1e-2b7d5a0e3f18" \ -d '{ "depositPercent": 30 }'POST
/provider/bookings/{id}/declineRifiuta una prenotazione in attesa, con motivo e messaggio
Permesso:
bookings:writeGET
/provider/calendar?month=YYYY-MML’agenda di un mese: feste, eventi aggiunti a mano, impegni importati (source: external) e giorni bloccati
Permesso:
calendar:readEsempio di risposta { "month": "2026-10", "entries": [ { "id": "bkg_m3x8q2", "source": "booking", "bookingId": "bkg_m3x8q2", "code": "YU-7KQ2XH", "status": "confirmed", "date": "2026-10-17", "startTime": "16:00", "durationMinutes": 120, "customerName": "Giulia Esposito", "serviceTitle": "Festa di compleanno con il mago", "town": "Napoli", "assignees": [ { "id": "stf_2p7w9z", "name": "Marco Russo" } ], "entertainersNeeded": 1, "venueId": null }, { "id": "ext_9d1f6b", "source": "external", "bookingId": null, "code": null, "status": "confirmed", "date": "2026-10-20", "startTime": "10:00", "durationMinutes": 90, "customerName": "", "serviceTitle": "Impegno privato", "town": "", "assignees": [], "entertainersNeeded": 0, "venueId": null } ], "blocks": [ { "date": "2026-10-25", "note": "Ferie", "managedBy": "provider" } ], "calendarMode": "self_managed" }GET
/provider/clients?q=&page=Clienti, con numero di feste e spesa totale
Permesso:
clients:readEsempio di risposta { "items": [ { "id": "cus_8h2k4d", "source": "site", "name": "Giulia Esposito", "email": "giulia@example.com", "phone": "+39 333 000 0000", "town": "Napoli", "bookings": 2, "lastPartyDate": "2026-10-17", "totalCents": 52000 } ], "page": 1, "pageSize": 20, "total": 1 }GET
/provider/quotes?status=&page=Preventivi; status: draft, sent, accepted, declined, expired
Permesso:
quotes:readEsempio di risposta { "items": [ { "id": "quo_5b8n3v", "number": "P-2026-014", "status": "sent", "client": { "id": "cli_1s6j0e", "name": "Anna De Luca", "email": "anna@example.com", "phone": "+39 347 000 0000" }, "title": "Comunione di Sofia: animazione e truccabimbi", "eventDate": "2026-11-08", "totalCents": 45000, "validUntil": "2026-10-08", "sentAt": "2026-09-24T09:30:00+02:00", "outcome": null } ], "page": 1, "pageSize": 20, "total": 1 }GET
/provider/servicesI tuoi servizi, con stato e statistiche degli ultimi 30 giorni
Permesso:
services:readEsempio di risposta [ { "id": "svc_4r9t1c", "slug": "festa-di-compleanno-con-il-mago", "title": "Festa di compleanno con il mago", "category": "feste-bambini", "status": "published", "fromPriceCents": 18000, "stats": { "views30d": 412, "requests30d": 9 }, "sponsorship": null, "pendingChanges": false, "photo": { "id": "pho_3k7m2x", "url": "https://yuppi.now/media/pho_3k7m2x.webp", "alt": "Il mago con i bambini" } } ]
Webhook
Aggiungi un webhook dal Gestionale: scegli l’indirizzo https che riceve le chiamate e gli eventi che ti interessano. Al massimo 5 webhook per account.
Per ogni evento Yuppi manda una richiesta POST con un corpo JSON: id dell’evento, tipo, istante e i dati in data. Con “Prova” ricevi un evento ping.
| Evento | Quando arriva | Contenuto di data |
|---|---|---|
| booking.created | Una famiglia manda una richiesta di prenotazione | { "booking": ProviderBooking } |
| booking.confirmed | Confermi una prenotazione | { "booking": ProviderBooking } |
| booking.cancelled | Una prenotazione viene annullata, da te o dalla famiglia | { "booking": ProviderBooking } |
| quote.accepted | Il cliente accetta un preventivo | { "quote": QuoteSummary } |
| quote.declined | Il cliente rifiuta un preventivo | { "quote": QuoteSummary } |
| deposit.paid | Una caparra viene pagata | { "booking": ProviderBooking } | { "quote": QuoteSummary } |
| review.published | Viene pubblicata una recensione su un tuo servizio | { "review": Review, "serviceId": string } |
| ping | Premi “Prova” nel Gestionale | {} |
{
"id": "evt_2w9c4r",
"type": "booking.confirmed",
"createdAt": "2026-09-20T11:03:02+02:00",
"data": {
"booking": {
"id": "bkg_m3x8q2",
"code": "YU-7KQ2XH",
"status": "confirmed",
"service": {
"id": "svc_4r9t1c",
"title": "Festa di compleanno con il mago"
},
"package": {
"name": "Festa completa",
"durationMinutes": 120,
"maxChildren": 25
},
"date": "2026-10-17",
"startTime": "16:00",
"address": "Via Toledo 120",
"town": "Napoli",
"children": 18,
"ageBand": "4-7",
"notes": "Festa a tema pirati, torta alle 17:30",
"customer": {
"id": "cus_8h2k4d",
"name": "Giulia Esposito",
"email": "giulia@example.com",
"phone": "+39 333 000 0000"
},
"totalCents": 28000,
"createdAt": "2026-09-20T10:12:00+02:00",
"respondBy": "2026-09-21T10:12:00+02:00",
"declineReason": null,
"timeline": [
{
"at": "2026-09-20T10:12:00+02:00",
"type": "created",
"by": "customer",
"note": null
},
{
"at": "2026-09-20T11:03:00+02:00",
"type": "confirmed",
"by": "provider",
"note": null
}
],
"assignees": [
{
"id": "stf_2p7w9z",
"name": "Marco Russo"
}
],
"entertainersNeeded": 1,
"deposit": {
"amountCents": 8400,
"status": "paid",
"paidAt": "2026-09-20T18:40:00+02:00"
},
"balance": {
"amountCents": 19600,
"status": "due",
"paidAt": null
},
"dispute": null,
"noShow": null,
"canMarkNoShow": false,
"canDispute": false
}
}
}{
"id": "evt_8m1q5z",
"type": "review.published",
"createdAt": "2026-10-19T09:00:00+02:00",
"data": {
"review": {
"id": "rev_6t2y8u",
"author": "Giulia E.",
"occasion": "Compleanno",
"partyDate": "2026-10-17",
"rating": 5,
"title": "Festa perfetta",
"body": "Bambini entusiasti dall’inizio alla fine.",
"reply": null
},
"serviceId": "svc_4r9t1c"
}
}Controllare la firma
Ogni chiamata ha l’intestazione Yuppi-Signature: l’HMAC-SHA256 del corpo della richiesta, così come arriva, calcolato con il segreto del webhook e scritto in esadecimale minuscolo.
Il segreto si vede per intero una volta sola, quando crei il webhook. Calcola la firma sul corpo grezzo, prima di leggere il JSON, e confrontala in tempo costante. Se non corrisponde, rispondi 401 e ignora la chiamata.
Yuppi-Signature: 3f9a0c6d1e...b27eimport { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: the body exactly as received (Buffer), before any JSON parsing
export function isFromYuppi(rawBody, signature, secret) {
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(String(signature ?? ''));
return a.length === b.length && timingSafeEqual(a, b);
}<?php
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, getenv('YUPPI_WEBHOOK_SECRET'));
if (!hash_equals($expected, $_SERVER['HTTP_YUPPI_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
http_response_code(200);Risposte e nuovi tentativi
Rispondi con un codice 2xx entro 10 secondi: fai il lavoro lungo dopo aver risposto.
Se il tuo indirizzo non risponde o risponde con un errore, riproviamo con attese sempre più lunghe per 24 ore. Nel Gestionale vedi le ultime 30 consegne, con stato e durata.
Lo stesso evento può arrivare più di una volta o in ordine diverso: usa l’id dell’evento per non elaborarlo due volte e l’istante createdAt per l’ordine.
Limiti
- 60 richieste al minuto per chiave. Oltre, rispondiamo 429 con Retry-After.
- Al massimo 10 chiavi API e 5 webhook per account.
- Le chiavi e i webhook funzionano finché il piano Pro o Agency Suite è attivo.