Configure access
In venue fulfillment settings, configure the Public channel with a published sales channel, active service actor, public handle and allowed origins. Configure contact verification and the required fulfillment policies. This flow uses guest draft and manage capabilities, not a partner key.
Cabinet route: /venues/:venueId/settings/fulfillment → Resources → Public channel. Public-channel configuration requires preorders.external.manage; fulfillment policies require preorders.policies.manage.
The catalog's fulfillmentOptions lists currently configured off-premise serviceMode/timingModes pairs. Choose PICKUP or DELIVERY only when returned with the intended ASAP or SCHEDULED timing. For DELIVERY, use the separately returned deliveryMethods choices. An empty fulfillmentOptions list means no public off-premise policy is configured. These hints reserve no capacity and do not bypass channel allowedOrigins, menu eligibility, delivery-zone or quote validation.
A widget reads catalog/availability and creates a draft with the actual isolated frame Origin and current x-hallify-widget-context. This proof binds exact parent/connection/resource, not draft/manage ownership. Original replay and private continuation retain native provenance and deadlines without requiring proof renewal. The SDK uses the same canonical contracts without cookies or an Origin override.
First successful workflow
Follow these steps in order. Open each method for its exact body, required headers and response schema.
The public catalog is a bounded typed projection of one published menu for one native venue and sales channel. Use its published selections, availability, menu version and opaque graph token. Prices and configuration remain subject to the native quote; public fields do not expose cost, stock or staff policy. Browser requests preserve their actual Origin and omit account credentials. When entering through Storefront ordering, retain its exact connection/resource/venue/channel locator and send connectionId as the declared nonsecret x-hallify-connection-id on draft issuance, including on the canonical Hallify Origin. It cannot replace catalog allowedOrigins or the presentation binding captured by an issued draft.
- Select the actual native public channel. If Storefront supplies ordering, use ordering.publicChannelHandle rather than the presentation handle and preserve all of its scoped locator fields.
- Read the catalog and fulfillmentOptions; compose a cart from eligible menu items, variants, modifiers and component selections. Preserve the exact menu version, opaque graph token, venue currency and time zone.
- Choose an admitted timing mode. For SCHEDULED, read bounded availability and use a selected slot's startsAt as scheduledFor. For ASAP, send timingMode: 'ASAP' and omit scheduledFor entirely; the server selects the promise during quote creation.
- Create a draft with Idempotency-Key. Retain draftReference, the draft Bearer token and its original timing/presentation context. Use the same key and exact body for a retry.
- Verify contact through the native draft flow. Review the returned single-use quote, including the frozen scheduledFor, lines, totals, currency, deposit requirements and expiresAt. Explicitly accept that exact quote before its deadline; the docs send no OTP or acceptance request.
- Exchange the returned one-time manage grant for a manage Bearer token. Read the original fulfillment, retained timingMode, scheduledFor and allowed actions; original acceptance/replay never searches for a replacement time.
- If guest payment is enabled and current authority permits it, follow the separate existing checkout consent flow. Creating an order does not itself accept financial consent or prove payment.
- For a permitted change, quote the amendment and accept it at the expected revision; cancel only within the guest cancellation policy.
- Get the publicly eligible preorder catalog
- Read bounded public scheduled fulfillment slot choices
- Create an encrypted public preorder draft
- Resume a public preorder draft
- Update and re-verify a public preorder draft
- Verify contact and issue a commercial quote
- Accept a single-use public preorder quote
- Exchange a URL-safe grant for a manage session
- View the guest-owned preorder projection
Keep published configuration and private draft state together
Build each cart line from the catalog's actual menuItemId/menuVariantId and applicable modifierOptionIds/componentSelections. Follow the published structure, required groups, choice cardinalities, variants and availability rather than inventing selectable IDs or prices. Keep a stable clientLineId and quantity for each line. The public numeric selling prices remain display input; the native quote determines authoritative commercial amounts.
Create/update use the same ASAP-or-scheduled body union. An update replaces the eligible cart/contact/fulfillment selection and invalidates the previous quote; protected contact changes restart verification. Read the saved draft to restore its original request and current quote. Do not silently substitute the current menu version, rebuild a pending request after a lost response or move a draft to another venue/channel.
Draft and manage credentials remain separate and private in their owning domain. Keep draft/contact bodies and capability-bearing replies outside Redux, URLs, cookies, logs and analytics. All snippets and reference examples are synthetic, are not executed by the docs and do not send an order, OTP, payment or courier request.
Choose explicit ASAP or retain the scheduled request
Scheduled input uses PublicPreorderScheduledDraftBodyDto with an exact explicit-offset scheduledFor. timingMode: 'SCHEDULED' is optional: omitting it preserves the legacy scheduled body and original request fingerprint. Do not insert it during retries of an originally omitted field. ASAP uses PublicPreorderAsapDraftBodyDto, requires timingMode: 'ASAP', supports only PICKUP/DELIVERY and forbids scheduledFor as a property, including null.
At quote creation, ASAP asks the server for the earliest native-admitted promise within 120 minutes of resolution. The calculation includes native lead time, published package calendars and cutoff rules, delivery-zone constraints and venue capacity. It requires at least five minutes of planning/review margin at resolution. This is a bounded search, not an unconditional delivery promise; the server can report no eligible time.
The quote freezes its fulfillment promise together with draft generation, original request/policy hashes and a safe acceptance deadline. Show the returned scheduledFor and expiresAt; the planning margin does not reset when the response arrives. Acceptance and original replay reuse that exact evidence and never search for a later slot. If the quote is stale or expired, require an explicit new review/quote under current rules rather than silently rescheduling.
Explicit timingMode is retained through draft request, quote, acceptance result and manage projection. Legacy scheduled records may omit it. Staff requests and amendment contracts keep their existing behavior; do not add ASAP fields to them. The following synthetic objects illustrate timing fragments only, not complete requests or available real slots.
const asapTiming = {
serviceMode: 'PICKUP',
timingMode: 'ASAP',
};
const scheduledTiming = {
serviceMode: 'DELIVERY',
timingMode: 'SCHEDULED',
scheduledFor: '2030-01-15T12:00:00+04:00',
};Choose a scheduled fulfillment slot
Read availability with the public handle, serviceMode, partySize and an explicit-offset RFC 3339 from/to window. Supported scheduled modes are PICKUP, DELIVERY and CATERING; the venue must have a current policy for the selected mode. Browser requests preserve their actual Origin. If a Storefront presentation is selected, send its nonsecret x-hallify-connection-id locator; the exact current connection and PREORDER resource are checked even on the canonical Hallify Origin.
The window is at most seven elapsed days and applies to slot starts: from is inclusive and to is exclusive. A returned slot may end after to. The response supplies the native venue time zone, currency and complete chronological choices, up to 500 slots. Oversized source or choice cohorts fail instead of being truncated; request a smaller window where appropriate.
Pass the chosen startsAt as scheduledFor and keep partySize consistent with the draft. available describes current venue-wide capacity for that party; this read creates no hold or reservation. The authoritative quote also validates the current cart, delivery area and fulfillment policy before acceptance. If the menu changed, reload the catalog and rebuild the affected choices with its current version and opaque graph token.
Open separate payment access for an eligible native order
In /venues/:venueId/settings/fulfillment → Resources → Public channel, an authorized operator must explicitly enable allowGuestPayments; its default is false. An eligible configured merchant binding and current native collectible Orders are also required. This setting does not turn a draft, a quote or a READ observer grant into payment authority.
The PREORDER_MANAGE payment source uses the exact accepted native fulfillment UUID and its current private manage capability for an eligible ASAP or scheduled order. Follow the guest-payments guide to open separate payment access, review the server payee and offer, and explicitly accept the immutable manifest. Keep the source token on its original origin and use receiver-first handoff when the configured checkout origin differs.
Read the optional nullable manage.paymentActorReference for the private journal's stable sourceContextKey preorder:<hint>. Only verified initial public EXCHANGE/original CREATE lineage supplies this opaque lowercase SHA-256 reference; retain it across SESSION exchange and capability rotation. Missing/null or unprovable LEGACY lineage makes payment entry unavailable, with no fulfillmentId fallback. The reference partitions UI state only: it is not a capability or financial permission, and reading manage mints no access.
A preorder command and a payment command have separate keys, receipts and authority. Keep the original payment flow through reload or UNKNOWN, and read its original progress rather than creating another intent. Preorder cancellation is not a public guest financial refund, void or capture command.
Select native delivery and retain its original quote
An authorized administrator configures carrier connections and credential versions at /organizations/:organizationId/delivery-connections, then venue methods, fee policy and pickup bindings at /venues/:venueId/settings/delivery. The corresponding account APIs use /organizations/{organizationId}/delivery-connections and /organizations/{organizationId}/venues/{venueId}/delivery/policy or /delivery/bindings. They are private configuration APIs, outside the guest SDK. A configured route or LIVE environment does not prove provider activation, regional availability or successful live delivery.
Catalog and scheduled availability can return deliveryMethods containing SELF, UBER_DIRECT or WOLT_DRIVE. Choose only a returned method and send deliveryMethod for DELIVERY. Omitting deliveryMethod preserves the original SELF behavior; preserve that omission on an identical retry. Other service modes must omit it. Method hints are provisional and the native quote revalidates current routing, capacity and policy. Wolt Drive requires genuine dropoff latitude and longitude; an address string is not geocoding and placeholder coordinates are not a valid substitute.
Preserve the original draft, declared Idempotency-Key, exact body and any returned deliveryQuoteId through verification and quote acceptance. The customer delivery quote is distinct from the later staff dispatchQuoteId. Carrier demand preparation can return PREORDER_DELIVERY_QUOTE_UNKNOWN or PREORDER_DELIVERY_QUOTE_NOT_READY before a native quote is issued. A timeout or uncertain outcome requires explicit replay of the original endpoint with its unchanged request and capability; do not create a replacement draft or quote with a new key. Direct HTTP conflict details can identify the original preparation and delivery quote; SDK callers use SdkError.apiCode and retain their own original request, without assuming an error.details property.
Review the customer delivery fee in the authoritative native quote before acceptance. That accepted fee stays frozen in the order currency; a later staff carrier dispatch offer has its own provider cost, currency and expiry and cannot silently reprice the customer agreement. Retries do not renew either quote deadline. Once the original outcome is resolved, a material change or expired customer quote requires the normal new native quote and acceptance flow.
The managed preorder delivery projection can include method and tracking with normalized courier state, pickup/dropoff ETA and requiresAttention. Null or missing tracking does not prove failure, cancellation or payment. Carrier cancellation, uncertain dispatch and later courier progress remain separate from meal cancellation, refunds, deposit and native fulfillment actions. Staff quote, dispatch, cancellation, readback, local abort and their bounded histories remain authenticated cabinet operations; the guest SDK does not expose them.
State, retries and recovery
Draft creation does not create an order. Editing protected contact details restarts verification. Keep the draft token and manage token separate. A consumed or expired grant cannot bootstrap another session; use the owning guest access recovery process.
An idempotent replay retains the original business revision. A successor management capability can be absent when its continuation is no longer current; historical response fields do not restore expired or revoked authority. Use the explicit current continuation result before issuing another management command.