Queek docs

App manifest

Configure a Queek app with queek.app.toml, scoped access, webhooks, extensions and dashboard UI.

The CLI reads queek.app.toml as the local app configuration and maps it to the manifest accepted by Queek. A manifest requires a slug, name, [access].scopes list (which may be empty), and [app].install_url and [app].uninstall_url. The CLI's manifest validator is the source of truth for accepted keys and limits. Do not put secrets in this file.

A complete example

This is the manifest the app starter ships. It requests one read scope, subscribes to one webhook topic, defines one merchant setting and registers an embedded page.

queek.app.toml
slug = "my-app"
name = "My App"
distribution = "public"
icon = "wave"
developer = "You"

[listing]
description = "What your app does, in one sentence."
tagline = "One line for the listing."

[access]
scopes = ["merchant-business_profile-read"]

[webhooks]
topics = ["orders/updated"]
url = "https://my-app.example.com/webhooks"

[app]
install_url = "https://my-app.example.com/install"
uninstall_url = "https://my-app.example.com/uninstall"
settings_url = "https://my-app.example.com/settings"

[[settings]]
key = "greeting"
label = "Greeting"
type = "string"
required = false
help = "Logged when an order update arrives."

[extensions]
merchant_page_url = "https://my-app.example.com/admin"

[dev]
command = "node ./server.js"
port = 3000

Use the same https origin for install_url, uninstall_url, settings_url, the webhook url and merchant_page_url. Run queek app deploy to validate the file: the CLI's validator is the source of truth, and it names the key and the limit when something is wrong.

Top-level TOML keys

The CLI accepts slug (or its handle alias), name, version, distribution, icon, developer, category, [listing], [access], [webhooks], [app], [[settings]], [extensions], [dashboard], and the CLI-only [dev] table. The version value is not used for deployment; the server assigns versions, or queek app deploy --version names one.

  • [listing] describes the app listing: description, tagline, long description, highlights, logo, pricing, developer, privacy, support, demo, and video URLs.
  • [app] contains install_url, uninstall_url, and optional settings_url endpoints.
  • [webhooks] contains topics and an optional app webhook URL.
  • [[settings]] defines merchant settings. A setting may use type = "secret"; the secret value belongs in the app's runtime configuration, not the manifest.
  • [dev] tells queek app dev how to start the local server and which port it uses.

Access scopes

[access]
scopes = ["merchant-orders-read"]
optional_scopes = ["merchant-products-read"]

scopes are requested at install. optional_scopes are available for the app to request later; they are not granted during installation. The two lists must be disjoint. An app installation cannot be granted app-management, API-key, roles, users, employees, or point-of-sale scopes. Choose the smallest set that supports the app's task, then call only operations those grants allow. See the Merchant API scopes.

Extensions

[extensions] accepts these entries:

  • [extensions.proxy] routes a configured storefront subpath to the app's HTTPS URL. The proxy serves GET. It serves signed POST only when allow_post = true is set and the merchant has accepted it (default false; installs made before the setting existed stay read-only until the merchant accepts the update). subpath must be 2–40 lowercase letters, digits, or dashes; share_customer_id is optional. Verify proxy requests with the SDK's proxy verifier. See Receiving storefront POSTs.

  • [[extensions.blocks]] declares storefront app_block or app_embed extensions. The CLI allows at most 10, targets are product, and available_if can use declared_products. Block settings use the supported date, time, select or line_text field types. A link URL or image can be included. A line_text block holds only line_text fields, needs available_if = "declared_products", and needs no proxy. A manifest declares at most 3 line_text fields, each with an optional max_length from 1 to 500 (default 100). A line_text field key may not be claim, reschedule_url or cancel_url. See Shopper text on a product line.

    Values a shopper types into a line_text field are untrusted input: the order line property is forgeable by design, so validate it in your app.

  • merchant_page_url is the embedded merchant page URL opened from the dashboard. How the page runs in the frame, and the messages it must send, are in Embedded apps and the dashboard bridge.

  • [[extensions.nav]] declares up to 10 navigation entries shown under the app in the dashboard sidebar. Each entry has a 1–40 character label and a relative path beginning with /; extensions.merchant_page_url is required when nav items are present.

Shopper text on a product line

A line_text field lets a shopper type a short text, such as an engraving or a gift note, that is stored on the order line. Three steps wire it end to end:

  1. Declare the field in the manifest. Add a line_text field with a key, a label and, optionally, required and max_length to a product block that sets available_if = "declared_products". A version that adds line_text goes through review.
  2. Declare which products take it. Call PUT /api/v1/merchant/app/line-inputs with the merchant-app-requirements-write scope. The body is the whole sheet, { "items": [{ "product_p_id": 1042, "fields": [{ "key": "engraving", "required": true, "max_length": 40 }] }] }. Each call replaces the previous sheet, so an empty items removes every declaration. A key must be a line_text field of the manifest the merchant granted. The label always comes from the manifest, and a max_length cannot exceed the manifest's. A sheet holds at most 200 products and 3 fields per product.
  3. Read the value on the order line. The text arrives in the line's properties under app.<handle>.<key>, where <handle> is the app's slug with dashes written as underscores. At checkout, a required field that is empty, or a value that is too long or contains control characters, is refused before payment. Orders a merchant's staff place themselves, such as at the point of sale, are not checked.

Queek derives the property key; an app never supplies it. Treat every value as untrusted shopper input: a client can send any property key and value, so check what you receive before you act on it, and never render it as HTML.

Receiving storefront POSTs

Set allow_post = true under [extensions.proxy] to let a storefront page submit data to your app, for example a form or a booking request. The merchant sees the setting on the install or update screen and has to accept it. Until they do, the proxy stays read-only for that store.

Queek relays POST <your proxy URL>/<path>?<signed query> with Content-Type: application/json and the shopper's body byte for byte. Cookies, the Authorization header, client keys, the Origin and the shopper's IP are never forwarded. The shopper's identity is forwarded only the way it is for reads, under share_customer_id.

Verify every POST before you act on it:

  1. Check sig exactly as you do for a read.
  2. Require the signed method parameter to equal POST.
  3. Compare the signed body_sha256 with the SHA-256 hex of the raw request body.
  4. Enforce the ts window and accept each jti once.
  5. Dedupe on the signed idempotency_key when it is present. A request that times out may still have been processed, so make your handler idempotent.

Answer with 200, 201, 202 or 204 and a JSON body, or with 400, 409 or 422 and a JSON body when the submission has errors the shopper can fix. Any other status, a body that is not JSON, or a timeout reaches the shopper as app_proxy_failed (424). The shop parameter is the store's opaque id.

Dashboard blocks, actions and print

The optional [dashboard] table supports [[dashboard.blocks]], [[dashboard.actions]], and [[dashboard.print]] entries. Each list is bounded by the CLI validator:

EntryMaximumSupported target / fields
blocks10order-details or product-details; schema field types date, time, select, text, or slot-list.
actions10order-details; an action declares a granted scope, a notification URL, and the order_appointment effect.
print5order-print; up to 20 print fields per entry.

Dashboard blocks and actions can include visibility conditions supported by the validator: order.has_appointment, order.is_paid, or product.has_files. Declare a scope required by an action in either scopes or optional_scopes.

The CLI rejects unknown keys and values outside these supported forms. Run queek app deploy --help and validate the manifest with queek app dev before submitting it.

Limits at a glance

ItemLimit
name120 characters
Setting label and each options entry120 characters
[[extensions.blocks]]10 entries, each descriptor at most 4,096 bytes
line_text fields3 per manifest; max_length 1–500 (default 100)
[[extensions.nav]]10 entries, label 1–40 characters
extensions.proxy.subpath2–40 lowercase letters, digits or dashes
extensions.proxy.allow_postboolean, default false; JSON POST bodies up to 65,536 bytes; 20 submissions per minute per shopper IP, 600 per installation
[[dashboard.blocks]], [[dashboard.actions]]10 entries each
[[dashboard.print]]5 entries, up to 20 fields each
Extension URLshttps, at most 2,048 characters

On this page