> ## 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.

# Writing a Prompt That Works

> The five-part prompt structure the storekit recipes use, plus the shared context block that tells Lovable, Bolt, Replit or v0 how webhooks arrive.

AI app builders do what you ask, and guess the rest. A vague prompt gets you a pretty screen that never receives an order. The prompts in our recipes follow one structure so the guessing is done before you paste. Use the same structure for your own ideas.

## The Structure

Every prompt has five parts, in this order:

1. **The outcome**, in one paragraph, as you would describe it to a new manager. Who uses it, where it runs, what it must never do.
2. **The storekit context block** below — copied in full. It tells the builder exactly how storekit will talk to the app, so it does not invent a payload or skip signature checks.
3. **What to build**, as a numbered list. Name the endpoint path, every screen, every rule. If you would check something when testing, it belongs on this list.
4. **Definition of done**, as checkboxes. The builder will use this to test its own work.
5. **What to hand back**: the public webhook URL, the list of environment variables you must set, and how to test it.

Keep the whole thing in one message. Follow-up messages are for fixing what the first one got wrong, not for adding the requirements you forgot.

## The Context Block

Paste this into every prompt, unchanged, straight after your outcome paragraph. It is the same block used in all the recipes.

```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 always has the shape { "event": "<event type>", "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 and deliveryAddress can be null. notes can be null or empty.

Example order.created payload:

{
  "event": "order.created",
  "data": {
    "id": "ord_abc123",
    "code": "A1B2",
    "asap": true,
    "total": 2500,
    "tip": 250,
    "deliveryFee": 299,
    "discountTotal": 0,
    "orderType": "Pickup",
    "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",
        "price": 1200,
        "quantity": 1,
        "plu": null,
        "posId": null,
        "taxRate": null,
        "modifiers": []
      }
    ],
    "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 }
      }
    },
    "table": {
      "id": "tbl_123",
      "name": "Table 5",
      "covers": 4,
      "posId": "pos_tbl_5",
      "area": { "id": "area_1", "name": "Main Floor", "posId": null }
    },
    "deliveryAddress": {
      "street1": "456 Oak Ave",
      "street2": "Flat 2",
      "city": "London",
      "postCode": "E1 6AN",
      "country": "UK",
      "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
```

If your tool uses an event other than `order.created`, copy that event's example payload from the [events reference](/docs/developers/webhooks/webhook-events) and add it under "Example payload" too.

## Rules Worth Repeating

Builders forget these unless the prompt is explicit, so every recipe spells them out. Copy the lines you need into part 3 of your prompt.

* Verify the Svix signature on every request using the official `svix` library. Do not write your own verification. Return 400 when it fails.
* Return 200 as soon as the event is stored, then process it. Never make storekit wait on a printer, a text message or a third-party API.
* Ignore any `svix-id` you have already seen.
* Keep the event history in a real database, not in memory, so nothing is lost when the app restarts or redeploys.
* Do not send customer names, phone numbers or addresses to any third-party service unless the prompt says so.
* Format money by dividing by 100 and using the venue's currency.
* Show times in the venue's local time zone, not the server's.
* Put the webhook secret and any API keys in environment variables. Never in the code.

## Choosing a Builder

We do not recommend one builder over another for everything, but the recipes note where it matters:

* **Tools that receive webhooks** need a stable public URL that stays up and, usually, a database. [Replit](https://replit.com) gives you all three in one place, so recipes that receive events are written with Replit in mind. Bolt and Lovable can do it too if you attach a backend (Supabase is the usual pairing); when you prompt them, add "deploy the backend so it has a public URL, and tell me what it is".
* **Screen-only tools** that read from a database your other tool writes to suit [Lovable](https://lovable.dev) and [v0](https://v0.dev) well.
* **Scheduled jobs** (a daily summary at 23:30, a weekly digest) need somewhere to run a scheduler. Ask the builder outright: "this must run every day at 23:30 Europe/London; tell me how you have scheduled it and how I can confirm it ran".

Whichever you choose, check the builder's own documentation for how it stores secrets and shows you the deployed URL — the names change more often than this page does.

## Connecting the Finished App

Once the builder gives you a URL, connect it:

<Steps>
  <Step title="Open the webhooks portal">
    In the dashboard sidebar, go to **Settings** → **Developers** and click **Manage Webhooks** (it reads **Enable Webhooks** the first time). Webhooks are a subscription feature — if you see **Upgrade to enable webhooks**, [contact support](/docs/getting-started/contact-support) first.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## Testing Without Waiting for a Real Order

* The test-delivery option in the webhooks portal uses a generic sample, not your menu. It proves the connection and the signature check; it does not prove your layout.
* For a real payload, place a small order on your own storefront with a test payment method or a 100% discount code, then refund it. Do this while the app's log is open.
* Deliberately break something once: change `STOREKIT_WEBHOOK_SECRET` to a wrong value and confirm the app returns 400 and the portal shows the failed delivery. Put the right value back.

## When the Builder Gets It Wrong

Paste the error, not a description of it. Most fixes are one of:

* "It says 400 in the storekit delivery log." The secret in the app does not match the endpoint's secret, or the app is parsing the body before verifying it. Tell the builder: "verify the raw request body, exactly as received, before parsing JSON".
* "It printed twice / texted twice." The app is not checking `svix-id`, or is doing the work before returning 200 and timing out. Tell the builder both rules again.
* "It worked, then stopped after a day." The app went to sleep or the history was in memory. Ask for an always-on deployment and a database.
* "Prices are 100 times too big." Minor units — remind it to divide by 100.


## Related topics

- [Payout Reconciliation Sheet](/docs/guides/build/recipes/payout-reconciliation.md)
- [Live Order Board for the Pass](/docs/guides/build/recipes/live-order-board.md)
- [Order Alerts to Slack or Your Phone](/docs/guides/build/recipes/order-alerts.md)
- [Out-of-Stock Log and Morning Digest](/docs/guides/build/recipes/out-of-stock-log.md)
- [Custom Kitchen Ticket on a Star Cloud Printer](/docs/guides/build/recipes/custom-kitchen-ticket.md)
