Skip to content
Get API key

API reference

Menu API

The menu as one outlet sells it: prices and availability resolved for that outlet. Only products enabled for online ordering with a fixed price are listed.

The response carries an ETag. Send it back as If-None-Match and an unchanged menu answers 304 Not Modified with no body. A 304 counts as an answered call.

Retrieve the menu

GET/api-v1-menu

Categories, products with variants and modifier group ids, modifier groups with options, and combo slots for one outlet.

Unlike the other reads, the body is the menu itself, not wrapped in data, and it has no request_id field; the x-request-id header still carries it.

Query parameters

NameTypeRequiredDescription
location_iduuidRequiredThe outlet whose menu you want.

Headers

NameTypeRequiredDescription
If-None-MatchstringOptionalThe ETag from a previous response.

Response fields (200)

NameTypeDescription
categories[]arrayid, name, sort_order.
products[]arrayid, name, description, category (the category’s name), image_url, price (the outlet’s price), is_available, variants[] { id, name, price }, modifier_groups (ids).
modifier_groups[]arrayid, name, required, min_select, max_select, options[] { id, name, price }.
combos[]arraycombo_product_id, slot_name, component_product_id, quantity.
generated_attimestampWhen this copy was built. Not part of the ETag.

Errors

Every error answers { "error": { "code", "message", "request_id" } }. Branch on code; see Errors for retrying.

HTTPCodeWhen
400invalid_requestlocation_id is missing.
400validation_failedlocation_id is not a UUID.
401invalid_keyThe Authorization header is missing, malformed, or the key is revoked or inactive.
402payment_requiredThe business’s plan does not include API access (Sansflow Premium). The key itself is fine.
403insufficient_scopeThe key does not carry the scope this endpoint needs, or it is pinned to a different outlet.
429rate_limitedOver the key’s per-minute limit (60 for sf_test_, 300 for sf_live_). Wait the seconds in Retry-After.
404location_not_foundlocation_id is unknown or inactive for this business.
500internal_errorSomething failed on our side. Quote the request_id when you report it.
Request
curl -G "https://ewpuclvmnygoddunkyrb.supabase.co/functions/v1/api-v1-menu" \
  -H "Authorization: Bearer $SANSFLOW_API_KEY" \
  --data-urlencode "location_id=3f6c2a1e-8b4d-4c2a-9e51-7a0d2b6c9f10"
Response200 OK

Headers: ETag: "sha256:…", Cache-Control: private, max-age=0, must-revalidate

{
  "location_id": "3f6c2a1e-8b4d-4c2a-9e51-7a0d2b6c9f10",
  "categories": [
    {
      "id": "8a0c2e4f-6b1d-4f7a-9c38-2e4a6c8e0f92",
      "name": "Kopi",
      "sort_order": 0
    }
  ],
  "products": [
    {
      "id": "f1b3d5a7-9c2e-4a6b-8d14-7e3c5a9b1d68",
      "name": "Kopi Susu",
      "description": null,
      "category": "Kopi",
      "image_url": null,
      "price": 25000,
      "is_available": true,
      "variants": [
        {
          "id": "6e8a0c2d-4f1b-4d5e-8a96-0c2e4a6b8d81",
          "name": "Iced",
          "price": 27000
        }
      ],
      "modifier_groups": [
        "8a0c2e4f-6b1d-4f7a-9c38-2e4a6c8e0f92"
      ]
    }
  ],
  "modifier_groups": [
    {
      "id": "8a0c2e4f-6b1d-4f7a-9c38-2e4a6c8e0f92",
      "name": "Extra",
      "required": false,
      "min_select": 0,
      "max_select": 2,
      "options": [
        {
          "id": "9b1d3f5a-7c2e-4a8b-8d49-3f5b7d9f1a03",
          "name": "Extra shot",
          "price": 3000
        }
      ]
    }
  ],
  "combos": [
    {
      "combo_product_id": "2d4f6b8c-0e1a-4c3d-9f57-8b9d1e3f5a70",
      "slot_name": "Drink",
      "component_product_id": "f1b3d5a7-9c2e-4a6b-8d14-7e3c5a9b1d68",
      "quantity": 1
    }
  ],
  "generated_at": "2026-11-08T03:00:00Z"
}

Example values. Run replays this response here; nothing is sent.

Base URL, keys and conventions: API reference overview.

Stuck? Quote the request_id from the response and write toSansflow support.Checked against API v1 on .