> ## Documentation Index
> Fetch the complete documentation index at: https://storekit.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Scrivere un prompt che funziona

> La struttura di prompt in cinque parti delle ricette storekit e il blocco di contesto che spiega a Lovable, Bolt, Replit o v0 come arrivano i webhook.

Gli app builder AI fanno ciò che chiedi e tirano a indovinare il resto. Un prompt vago ti restituisce una bella schermata che però non riceve mai un ordine. I prompt nelle nostre recipe seguono un'unica struttura, così l'incertezza è già stata risolta prima di incollarli. Usa la stessa struttura per le tue idee.

## La struttura

Ogni prompt ha cinque parti, in quest'ordine:

1. **Il risultato**, in un paragrafo, come lo descriveresti a un nuovo manager. Chi lo usa, dove gira, cosa non deve mai fare.
2. **Il blocco di contesto storekit** qui sotto — copiato per intero. Dice al builder esattamente come storekit parlerà all'app, così non inventa un payload né salta la verifica delle firme.
3. **Cosa costruire**, come elenco numerato. Nomina il path dell'endpoint, ogni schermata, ogni regola. Se controlleresti qualcosa in fase di test, deve essere in questa lista.
4. **Definition of done**, come checkbox. Il builder le userà per testare il proprio lavoro.
5. **Cosa restituire**: l'URL webhook pubblico, l'elenco delle variabili d'ambiente da impostare e come testarlo.

Tieni tutto in un unico messaggio. I messaggi successivi servono per correggere ciò che il primo ha sbagliato, non per aggiungere requisiti che avevi dimenticato.

## Il blocco di contesto

Incolla questo in ogni prompt, senza modifiche, subito dopo il paragrafo del risultato. È lo stesso blocco usato in tutte le recipe.

```text theme={null}
CONTEXT ABOUT STOREKIT

I run a hospitality business on storekit (storekit.com), an online ordering and payments platform for restaurants, cafés and bars. storekit can notify my own app about things that happen in my store by sending webhooks.

How storekit webhooks work:
- Each event is an HTTP POST with a JSON body to a URL I register in the storekit dashboard.
- The body has the shape { "event": "<event type>", "data": { ... } }. Two exceptions: the legacy order.created event (do not use it; use order.created.v2) sends the bare order object, and the order.refund.created / order.refund.succeeded / order.refund.failed events put order, customer, venue and refund next to event instead of inside data.
- Requests are signed with Svix. Every request carries the headers svix-id, svix-timestamp and svix-signature. Verify them with the official `svix` library for your language, using a secret I will provide in an environment variable called STOREKIT_WEBHOOK_SECRET. Reject anything that fails verification with HTTP 400.
- My endpoint must respond with a 2xx status within 15 seconds. Save the event to the database first, respond 200, then do the work from the saved copy.
- Once I have responded 200, storekit will not send that event again, so the work must not be lost: store each event with a status (pending, done, failed) and only mark it done after the work has actually succeeded. On startup and on a timer, pick up anything still pending or failed and retry it. Never do the work only in memory after responding.
- The same event can occasionally be delivered more than once. Use the svix-id header as the unique key for the saved event: a repeat of an event already saved is ignored, whatever its status.
- Any page or endpoint protected by a password must be served over HTTPS only; redirect or refuse plain HTTP.
- Money fields (total, tip, deliveryFee, discountTotal, item price, modifier price) are integers in minor units: 2500 means £25.00.
- orderType is one of Delivery, Pickup, InStore, Curbside, CateringDelivery, CateringPickup or Billpay.
- table is only present for in-store orders; deliveryAddress and pickUpTime only for delivery orders. When they do not apply the key is omitted, so treat a missing key the same as null. notes and items[].note can be null or empty. customer.companyName and customer.vatNumber appear only when supplied.

Example order.created.v2 payload:

{
  "event": "order.created.v2",
  "data": {
    "id": "ord_abc123",
    "code": "A1B2",
    "asap": true,
    "total": 2500,
    "tip": 250,
    "deliveryFee": 299,
    "discountTotal": 0,
    "orderType": "Delivery",
    "pickUpTime": "2024-01-15T10:45:00Z",
    "channel": "WEB",
    "poNumber": null,
    "createdAt": "2024-01-15T10:30:00Z",
    "deliveryTime": "2024-01-15T11:00:00Z",
    "notes": "Ring doorbell",
    "customer": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com",
      "phone": "+44123456789",
      "marketingConsent": true
    },
    "items": [
      {
        "name": "Margherita Pizza",
        "printName": "Margherita",
        "price": 1200,
        "quantity": 1,
        "plu": null,
        "posId": null,
        "taxRate": 20,
        "note": null,
        "modifiers": [
          { "name": "Extra cheese", "printName": "Cheese", "price": 150, "quantity": 1, "plu": null, "posId": null, "taxRate": 20 }
        ]
      }
    ],
    "venue": {
      "id": 1234,
      "name": "My Restaurant",
      "slug": "my-restaurant",
      "address": {
        "street1": "123 Main St",
        "street2": "",
        "city": "London",
        "postCode": "W1A 1AA",
        "country": "UK",
        "companyName": "My Restaurant Ltd",
        "coordinates": { "latitude": 51.5074, "longitude": -0.1278 }
      }
    },
    "deliveryAddress": {
      "street1": "456 Oak Ave",
      "street2": "Flat 2",
      "city": "London",
      "postCode": "E1 6AN",
      "country": "UK",
      "notes": null,
      "coordinates": { "latitude": 51.5155, "longitude": -0.0722 }
    }
  }
}

The full list of event types and payloads is at https://storekit.com/docs/developers/webhooks/webhook-events
```

Se il tuo strumento usa un evento diverso da `order.created.v2`, copia l'esempio di payload di quell'evento dal [reference degli eventi](/docs/it/developers/webhooks/webhook-events) e aggiungilo anche sotto "Example payload".

## Regole da ripetere

I builder le dimenticano se il prompt non è esplicito, per questo ogni recipe le enuncia. Copia nella parte 3 del tuo prompt le righe che ti servono.

* Verifica la firma Svix di ogni richiesta usando la libreria ufficiale `svix`. Non scrivere la tua verifica. Restituisci 400 quando fallisce.
* Restituisci 200 non appena l'evento è salvato, poi elaboralo. Non far mai aspettare storekit su una stampante, un SMS o un'API di terze parti.
* Ignora ogni `svix-id` che hai già visto.
* Mantieni la history degli eventi in un vero database, non in memoria, così nulla va perso al riavvio o al redeploy dell'app.
* Non inviare nomi, numeri di telefono o indirizzi dei clienti ad alcun servizio di terze parti a meno che il prompt lo dica.
* Formatta il denaro dividendo per 100 e usando la valuta del locale.
* Mostra gli orari nel fuso orario locale del locale, non del server.
* Metti il webhook secret e ogni API key in variabili d'ambiente. Mai nel codice.

## Scegliere un builder

Non raccomandiamo un builder rispetto a un altro per tutto, ma le recipe indicano dove conta:

* **Gli strumenti che ricevono webhook** hanno bisogno di un URL pubblico stabile che resti attivo e, di solito, di un database. [Replit](https://replit.com) offre tutti e tre in un solo posto, per questo le recipe che ricevono eventi sono scritte pensando a Replit. Anche Bolt e Lovable possono farlo se attacchi un backend (l'abbinamento tipico è con Supabase); quando scrivi loro il prompt, aggiungi "distribuisci il backend in modo che abbia un URL pubblico e dimmi qual è".
* **Gli strumenti solo-schermo** che leggono da un database scritto da un altro tuo strumento si adattano bene a [Lovable](https://lovable.dev) e [v0](https://v0.dev).
* **I job schedulati** (un riepilogo giornaliero alle 23:30, un digest settimanale) hanno bisogno di un posto dove eseguire uno scheduler. Chiedilo esplicitamente al builder: "questo deve girare ogni giorno alle 23:30 Europe/London; dimmi come lo hai schedulato e come posso confermare che è stato eseguito".

Qualunque tu scelga, controlla la documentazione del builder stesso per capire come conserva i secret e ti mostra l'URL distribuito — i nomi cambiano più spesso di questa pagina.

## Collegare l'app finita

Una volta che il builder ti dà un URL, collegalo:

**1. Open the webhooks portal**

In the dashboard sidebar, go to **Settings** → **Webhooks**. If your plan includes webhooks and they are not yet enabled, click **Enable Webhooks**. If the page shows **Upgrade to enable webhooks**, [contact support](/docs/getting-started/contact-support) to discuss adding webhooks to your plan.

**2. Add your app as an endpoint**

In the embedded portal, add a new endpoint, paste the webhook URL your app builder gave you, and tick only the event types the recipe needs.

**3. Copy the signing secret into your app**

Open the endpoint you just created and copy its signing secret. In your app builder, save it as the environment variable `STOREKIT_WEBHOOK_SECRET` (builders call this "secrets" or "environment variables"). Redeploy if the builder asks you to.

**4. Send a test event**

Use the portal's test option on the endpoint to send a sample event. The delivery log shows the response code from your app. A `2xx` means your app accepted it; anything else, read the response body in the log — it is usually a missing secret.

## Testare senza aspettare un ordine reale

* L'opzione di test-delivery nel portale webhook usa un esempio generico, non il tuo menu. Dimostra la connessione e la verifica della firma; non dimostra il tuo layout.
* Per un payload reale, effettua un piccolo ordine sulla tua storefront con un metodo di pagamento di test o un codice sconto del 100%, poi rimborsalo. Fallo con il log dell'app aperto.
* Rompi qualcosa di proposito una volta: cambia `STOREKIT_WEBHOOK_SECRET` con un valore errato e conferma che l'app restituisca 400 e che il portale mostri la consegna fallita. Rimetti il valore corretto.

## Quando il builder sbaglia

Incolla l'errore, non una sua descrizione. La maggior parte delle correzioni è una di queste:

* "Il log delle consegne storekit dice 400". Il secret nell'app non corrisponde a quello dell'endpoint, oppure l'app sta parsando il body prima di verificarlo. Di' al builder: "verifica il raw request body, esattamente com'è ricevuto, prima di parsare il JSON".
* "Ha stampato due volte / inviato l'SMS due volte". L'app non controlla `svix-id`, o svolge il lavoro prima di restituire 200 e va in timeout. Ricorda al builder entrambe le regole.
* "Ha funzionato, poi si è fermato dopo un giorno". L'app è andata in sleep o la history era in memoria. Chiedi un deployment sempre attivo e un database.
* "I prezzi sono 100 volte più grandi". Minor units — ricorda di dividere per 100.


## Related topics

- [Foglio di riconciliazione dei payout](/docs/it/guides/build/recipes/payout-reconciliation.md)
- [Log esaurimenti e riepilogo mattutino](/docs/it/guides/build/recipes/out-of-stock-log.md)
- [Alert ordini su Slack o sul telefono](/docs/it/guides/build/recipes/order-alerts.md)
- [Board ordini in tempo reale per il pass](/docs/it/guides/build/recipes/live-order-board.md)
- [Kitchen ticket personalizzato su una stampante Star cloud](/docs/it/guides/build/recipes/custom-kitchen-ticket.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.