Przejdź do głównej zawartości

Zapytania (Queries)

Ten dokument opisuje kiedy używać każdej query w DoSwiftly Storefront API — pogrupowanej po obszarach biznesowych (sklep, produkty, koszyk, klient, lojalność itd.). Pełne sygnatury, zmienne, fragmenty i opisy renderuje komponent <OperationRef /> na podstawie @doswiftly/storefront-operations/operations.json — zero ręcznej duplikacji, zero driftu.

Szczegółowa referencja typów (objects / inputs / enums / scalars / interfaces / unions) jest w sekcji Types Reference<OperationRef /> linkuje do niej automatycznie z tabeli Variables. Wszystkie operacje są wstępnie zbudowane w pakiecie @doswiftly/storefront-operations i konsumowane przez @doswiftly/storefront-sdk — większości z nich nie musisz pisać ręcznie.

Filtrowanie obszarów

Komponent <OperationsList /> poniżej grupuje operacje per sekcja. Możesz też przefiltrować po jednej sekcji, np. <OperationsList section="Cart" />. Sekcje pochodzą bezpośrednio z SSOT pakietu operacji.

Shop

OperationKindDescription
ShopqueryReturns shop configuration: name, base + supported currencies, supported locales, branding (logo, colors, fonts, social links), contact info, active payment methods, brand metadata, money format template, and the list of countries the shop ships to. Public; no auth required. Call once per session and cache — almost everything else is contextualized by the shop returned here.
ShopConfigqueryMinimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules.

Products

OperationKindDescription
ProductqueryFetches a single product by `id` or `handle` (URL-friendly identifier). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).
ProductConfiguratorqueryFetches a product together with its configurator fields, optimized for the product-page configurator UI. filledBy CUSTOMER returns only the fields a shopper edits; pass BOTH to also include seller-prefilled fields. Single round-trip.
ProductsqueryPaginated product list (Relay Connection, default page size 20, max 100). The `query` argument supports a structured search syntax — `tag:summer`, `vendor:foo`, `product_type:shirts`, `variants.price:>10`, plus `AND`/`OR`/`NOT` — falling back to free-text title/content search. The `filters[]` array uses multi-filter logic: same field name appears multiple times → OR; different fields → AND. Sort: `RELEVANCE`, `TITLE`, `PRICE`, `NEWEST`, `OLDEST`, `BEST_SELLING`. The response includes a `filters` block for faceted navigation (counts per filterable attribute value).
ProductSearchqueryFull-text product search — `$query` is required. Functionally equivalent to `Products` with `$query` set, minus the `sortKey` argument (search defaults to relevance ranking). Use for the search results page; combine with `filters[]` for guided refinement.
SearchSuggestionsqueryType-ahead suggestions for the storefront search input. Returns up to `$limit` matching products (hard cap 50) plus up to 5 styled query suggestions with `<mark>` tags around matched spans. Polish-language aware (handles morphology in suggestions). Run on each keystroke (debounce 200-300ms). The `$query` is capped at 100 characters server-side.

Collections

OperationKindDescription
CollectionqueryFetches a single collection by `id` or `handle`, with paginated products. Collections come in two types: **MANUAL** (curated — products explicitly added by the merchant) and **AUTO** (rule-based — products matched dynamically). Both surfaces use the same field selection.
CollectionsqueryPaginated list of all active collections (default 20, max 100). Sort by `TITLE` or `UPDATED_AT` via `sortKey`. Note: the `query` argument is reserved for future text filtering — it is currently accepted but ignored.

Brands

OperationKindDescription
BrandqueryFetches a single brand by `id` or `handle` (e.g. "funko" → /brands/funko) together with its landing-page fields (name, logo, description, SEO) and a paginated slice of its products. Use for brand pages. Returns null when the brand does not exist or is archived. Public — no auth required.
BrandsqueryPaginated list of active brands (brand index / navigation), default 20, max 100. Sort by `NAME` (default), `PRODUCT_COUNT`, `CREATED_AT` or `UPDATED_AT`; set `reverse: true` to descend. Optional `query` filters by brand name. Public — no auth required.

Categories

OperationKindDescription
CategoryqueryFetches a single category by `id` or `handle` with its parent, immediate children, and a paginated slice of its products. Use for category landing pages (hero + breadcrumbs + product grid in one round-trip) and sub-navigation. Nested `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns. Public — no auth required.
CategoriesqueryReturns active root categories for the shop. Each root exposes its `children` — build the tree client-side by walking those fields (server batches the lookups, no N+1). The hierarchy is not depth-capped server-side. Use for nav mega-menus and category pages.

Cart

OperationKindDescription
CartqueryFetches a cart by `id` (the value persisted by the SDK in the `cart-id` cookie). The cart query is public — no auth needed to read it — but once a customer logs in and gets associated with the cart, mutations enforce ownership. Returns line items (paginated up to 100), totals, applied discount codes, gift cards, buyer identity, note, attributes, and warnings. Refetch after every cart mutation.

Customer (requires auth)

OperationKindDescription
CustomerqueryFull customer profile — basic info plus the first 10 addresses and first 10 orders. Heaviest customer query; for narrow use cases prefer `CustomerProfile` (no orders / addresses) or `CustomerOrder` (single order). Returns null if unauthenticated.
CustomerProfilequeryLightweight customer profile (no orders, no addresses list). Use for settings / profile pages that only need basic customer info — much cheaper than `Customer`. Returns null if unauthenticated.
CustomerAddressesqueryAuthenticated customer's saved address book — used on checkout to let the buyer pick a previously-used shipping / billing address instead of typing it. Each entry carries B2B invoicing fields (`taxId`, `vatNumber`) and the `isDefault` flag so the same list serves both as the shipping picker and as the billing/invoice picker. Returns up to 50 addresses (Relay Connection — buyers rarely keep more); for the unauthenticated case the connection is empty (no error). The default address is also surfaced as `Customer.defaultAddress`.
CustomerOrderquerySingle order by `orderId`. Returns only orders that belong to the authenticated customer (cross-customer access returns null, not an error). Much cheaper than fetching the full `Customer` payload to access one order. Use on the order detail page.
OrderByTokenqueryFetch a single order using its opaque access token (`Order.accessToken`) — designed for guest order summary pages where the buyer has not signed in. The token is returned in `cartComplete.order.accessToken` immediately after checkout completes; persist it in an HTTP-only cookie (preferred) or `sessionStorage` for the post-checkout page (NEVER `localStorage`). Optional `email` parameter adds defense-in-depth: when provided, it is matched case-insensitively against the order's buyer email; on mismatch the query returns `null` exactly like an invalid token (the response shape is identical, so an attacker cannot distinguish "token valid, wrong email" from "token invalid"). Rate-limited to 5 requests per minute per IP+shop combination to deter token enumeration; clients exceeding the limit receive a GraphQL error with `extensions.code: THROTTLED`. The response is marked `Cache-Control: no-store` so per-customer order data is never served from CDN or browser cache between users. Safe to retry; the token is permanent until the order is deleted.

Discount Code Validation

OperationKindDescription
CartValidateDiscountCodequeryRead-only validation of a discount code against an existing cart — does NOT modify cart state. Returns `{ isValid, discount, error }` (`DiscountValidationResult`) for previewing the effect of a code (inline UI feedback as the user types, before they commit to applying via `cartDiscountCodesUpdate`). Validates: discount existence + active status + customer eligibility + minimum order amount + minimum quantity met. Errors: `NOT_FOUND`, `INACTIVE`, `NOT_STARTED`, `EXPIRED`, `USAGE_LIMIT_REACHED`, `CUSTOMER_USAGE_LIMIT_REACHED`, `CUSTOMER_NOT_ELIGIBLE`, `MINIMUM_ORDER_NOT_MET`, `MINIMUM_QUANTITY_NOT_MET`.

Payment Methods

OperationKindDescription
AvailablePaymentMethodsqueryReturns the active payment methods for the shop, sorted by the merchant-configured display position. Shop-level — does NOT vary by cart amount or currency. Each method exposes `type` (`CARD`, `BANK_TRANSFER`, `BLIK`, `PAYPAL`, `APPLE_PAY`, `GOOGLE_PAY`, `CASH_ON_DELIVERY`, `OTHER`), provider, icon, description, and supported currencies. Use to render the payment step of checkout.
CartAvailablePaymentMethodsqueryCart-aware payment methods discovery. Returns the same active payment methods as the shop-level `availablePaymentMethods`, but with surcharge amounts resolved: a payment fee can be a percentage of the order value, so the exact amount (e.g. "+5 zł" or "+2.5% (7.18 zł)") is only computable against a cart. Prefer this once a cart exists (`cartCreate`); use the shop-level query for pre-cart previews (method grid, product page upsell) — there `fee` is always null, because the amount it would carry does not exist without a cart. Read `methods[].fee` for the whole-tile surcharge; when instruments carry different fees (e.g. per-brand card surcharges), read `methods[].instruments[].fee` per instrument instead. This query does NOT change cart state and is safe to retry; returns null when the cart does not exist.

Shipments / Tracking

OperationKindDescription
ShipmentqueryFetches a shipment by `id` with status, tracking events, recipient address, and shipped/delivered timestamps. **Auth required** — customer access token plus ownership of the parent order. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch to prevent enumeration), `FETCH_FAILED`.
ShipmentByTrackingNumberquery**Public** shipment lookup by carrier tracking number — no auth required. Designed for "Track my order" landing pages reachable without login. Returns the basic shipment fragment including recipient address. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_INPUT`, `NOT_FOUND`, `FETCH_FAILED`.

Returns / RMA

OperationKindDescription
ReturnqueryFetches a single return (RMA) by `id` with line items, refund/compensation info, and history. **Auth required** — customer access token plus ownership of the return. Wrapped response: `{ return, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch), `FETCH_FAILED`.
ReturnsByOrderqueryLists returns for a given order (paginated, default page size 20, cursor-based). **Auth required** — customer access token plus ownership of the order; the connection is empty (no explicit error) on auth failure. Use on the order detail page to show return history.
ReturnReasonsqueryReturns the standard list of return reasons used by the RMA flow: `DEFECTIVE`, `NOT_AS_DESCRIBED`, `WRONG_ITEM`, `CHANGED_MIND`, `BETTER_PRICE`, `DAMAGED_SHIPPING`, `OTHER`. The list is fixed across all shops — not per-shop configurable. Public; no auth required.

Gift Cards

OperationKindDescription
GiftCardqueryPublic gift-card lookup by `code`. Returns balance, currency, expiry, and `maskedCode` (first 4 + last 4 chars only — the full code never leaks back). Returns null if the code is unknown (rather than an explicit error, to limit enumeration). **Rate-limited**: 10 requests per 60 seconds per IP.
GiftCardValidatequeryValidates whether a gift card is usable (and optionally for a given `$amount`). Checks status (`DISABLED`, `USED`, `EXPIRED`), expiry date, and — when `$amount` is provided — sufficient balance. Returns `{ validation: { isValid, availableBalance, error: { code, message } }, userErrors[] }`. Validation error codes: `NOT_FOUND`, `DISABLED`, `ALREADY_USED`, `EXPIRED`, `INSUFFICIENT_BALANCE`. **Rate-limited**: 10 / 60s.

Shipping Methods

OperationKindDescription
AvailableShippingMethodsqueryReturns shipping methods for a given destination address and cart shape (subtotal, total weight, currency). The query computes everything from the inputs alone — no existing cart is required, so it can be used for "shipping cost preview" UIs (e.g. product detail page shipping calculator) before the customer adds anything to a cart. Each method includes price, free-shipping progress (`{ qualifies, currentAmount, threshold, remaining, progressPercent }`), estimated delivery, and carrier metadata. Sorted by the merchant's `sortOrder`, then by price. For a cart-bound checkout flow (where the cart is already known and the storefront wants the resolver to skip non-physical items and surface a `DIGITAL_ONLY_NO_SHIPPING` user error for all-digital carts), use `CartAvailableShippingMethods` against `cart.availableShippingMethods(address)` instead.
CartAvailableShippingMethodsqueryCart-aware shipping methods discovery. Returns shipping methods available for the cart's contents at the given destination, with subtotal and physical-item weight pulled from the cart aggregate (no need to compute them client-side). When the cart contains only non-physical items (digital, gift card, service, subscription), the response is `methods: []` plus a `DIGITAL_ONLY_NO_SHIPPING` user error — use this as the signal to skip rendering the shipping picker step. Prefer this query over the standalone `AvailableShippingMethods` once a cart has been created (`cartCreate`). For pre-cart "shipping cost preview" UIs on product detail pages, the standalone query remains the right tool.

Attribute Filters

OperationKindDescription
ProductFiltersqueryReturns the dynamic facet filters available for a listing context — pass `collectionId`, `categoryId`, `searchQuery`, optional `available` (boolean for the availability facet), and optional `currentFilters` (array of attribute filters currently applied by the UI). For each visible & filterable attribute, returns either discrete value counts (for `SELECT` / `CHECKBOX` types) or numeric range bounds (for `SLIDER` types). Plus `priceRange`, `brands`, per-category counts, `activeCount` (length of `currentFilters`), `totalCount` (products in context — Relay-aligned), and `availableCount` (boolean facet count for `availableForSale`). All per-facet counts use exclude-self aggregation: a facet's count IGNORES its own currently-applied filter and APPLIES other filters — so the count reflects "products if this facet were toggled" rather than "products currently visible". Untracked inventory (gift cards, digital, made-to-order) is always counted as available. Use to render filter sidebars on listing/search pages.

Loyalty Program

OperationKindDescription
LoyaltyMemberqueryReturns the logged-in customer's loyalty membership: points (current, pending, redeemed, expired, expiring), current tier, tier progress, annual spend, last activity. Returns null if the customer is not enrolled — there is **no auto-enrollment** here (enrollment happens via signup or a first qualifying order). Auth required.
LoyaltyTiersqueryLists the loyalty tiers configured for the shop (`BRONZE`, `SILVER`, `GOLD`, `PLATINUM`, `DIAMOND` etc.) with their `minPoints`, `minAnnualSpend`, `pointsMultiplier`, and custom benefits. Sorted by `minPoints` ASC. Public; no auth required.
LoyaltyRewardsqueryLists rewards customers can redeem (free shipping, percent off, free product, gift card). Filtered to **active** rewards only (`is_active = true` AND inside their `starts_at`/`ends_at` window). Public; no auth required.
LoyaltyTransactionsqueryPaginated history of loyalty point transactions for the logged-in customer (default 20). Transaction `type` enum: `EARN_PURCHASE`, `EARN_SIGNUP`, `EARN_REFERRAL`, `EARN_REVIEW`, `EARN_BIRTHDAY`, `EARN_BONUS`, `REDEEM`, `EXPIRE`, `ADJUST`, `REFUND_REVERSAL`. Auth required — empty connection if unauthenticated.
LoyaltySettingsqueryReturns the loyalty program configuration: `isEnabled`, `pointsName` (e.g. "stars"), `pointsPerCurrency`, `pointsExpiryMonths`, available earn actions, referral settings. Use this at app boot to decide whether to render any loyalty UI at all. Public; no auth required.
NewsletterIncentivequeryReturns the shop's newsletter signup incentive — when `isEnabled` is true, render the signup banner with the returned discount shape (e.g. "subscribe & get -10%"); a confirmed signup earns a personal, single-use code delivered by email (it works only for the address it was issued to). When false, hide the incentive messaging — plain newsletter signup still works. Public; no auth required.
EstimatePointsqueryEstimates how many loyalty points the customer would earn for an order of `$orderTotal` (in major currency units). When the customer is authenticated, the result accounts for their current tier's points multiplier. Use on cart/checkout to show "Earn X points with this order".
ReferralStatsqueryReturns the customer's referral statistics: `referralCode`, `shareUrl`, `totalReferred`, `completedReferrals`, `pendingReferrals`, `totalPointsEarned`. Auth required. Returns null if unauthenticated or if the referral program is disabled for the shop.

Reviews

OperationKindDescription
ProductReviewsqueryPaginated list of customer reviews for a product, **filtered to APPROVED reviews only** (PENDING / REJECTED reviews are not exposed to the storefront). Sort by `CREATED_AT` (default), helpfulness, or rating. Public; no auth required.
ReviewStatsqueryAggregate review statistics for a product: average rating, total count, distribution per star (1-5). Computed from APPROVED reviews only. Use for product card review summaries. Public; no auth required.

Wishlists

OperationKindDescription
WishlistsqueryPaginated list of the logged-in customer's wishlists (default 20). Auth required — empty connection if unauthenticated. Customers typically have a small set (<10).
WishlistByIdqueryFetches a single wishlist by `id`. Private wishlists are visible only to the owner; public wishlists are visible to anyone. Note: this query supports lookup by `id` only — there is currently no way to fetch a wishlist by its share token.

Blog

OperationKindDescription
BlogPostsqueryPaginated list of published blog posts. Filter by `categoryHandle`, `tagHandle`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.
BlogPostqueryFetches a single blog post by `id` or `handle`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).
BlogCategoriesqueryLists all blog categories with per-category `postCount` and SEO metadata. Use to render category navigation on blog pages. Public; no auth required.
BlogTagsqueryLists blog tags with usage counts (`postCount` per tag). Use to render a tag cloud. Public; no auth required.
BlogCategoryqueryFetches a single blog category by `id` or `handle`, including its image and SEO metadata. Use on a category landing page (the paginated post list for the category comes from `BlogPosts` with `categoryHandle`). Public; no auth required.
BlogTagqueryFetches a single blog tag by `id` or `handle`, including its SEO metadata (null when the merchant has not set any). Use on a tag landing page (the paginated post list for the tag comes from `BlogPosts` with `tagHandle`). Public; no auth required.
BlogPostProductsqueryProducts the merchant pinned to a blog post — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip inside or below the post. Public; no auth required.
BlogCategoryProductsqueryProducts the merchant pinned to a blog category — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip on the category landing page. Public; no auth required.
BlogTagProductsqueryProducts the merchant pinned to a blog tag — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip on the tag landing page. Public; no auth required.

Recommendations

OperationKindDescription
ProductRecommendationsqueryReturns up to `$limit` recommended products related to `$productId`. Default `$intent: SIMILAR` — products sharing categories or tags. Use on PDP "You may also like" sections. Public; no auth required.

Content: Pages

OperationKindDescription
PagequeryFetches a single CMS page (About, Privacy, Returns Policy, Terms, etc.) by `handle` or `id`. Visibility-gated: returns null if the page is hidden or if its publish date is in the future. Public; no auth required.
PagesqueryPaginated list of visible, already-published CMS pages. Use for sitemap, footer link list, or page directory. The `query` argument supports text search over the page title/handle. Public; no auth required.

Content: Navigation Menus

OperationKindDescription
MenuqueryFetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree (up to 3 levels). Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, `PAGE`, or `BRAND` — switch on the type to render the right link target. Each resource-linked item exposes both a pre-resolved `url` (standard `/categories|/collections|/pages|/products|/brands/<handle>` convention) and a typed `resource` union with the raw handle so storefronts with custom routing can construct their own paths instead. All resource lookups are batched per request — no N+1 even for deep menus.

Content: URL Redirects

OperationKindDescription
UrlRedirectsqueryReturns the shop's URL redirects (legacy `path` → new `target` mappings). Use server-side at the edge or in SSR to issue 301 redirects for migrated routes (preserves SEO equity). Default page size 250 — most shops fit in a single page.

Store Availability: per-location stock (BOPIS / multi-location)

OperationKindDescription
ProductStoreAvailabilityqueryFetches a product (by `handle` or `id`) along with per-variant availability across the merchant's physical locations — for the BOPIS / multi-location flow. The `storeAvailability` connection lives on each `ProductVariant`; its arguments (`first`, `after`, `near`, `locationType`) are set inside the `VariantStoreAvailability` fragment. The connection returns null for single-location shops (in which case the storefront can skip the store picker entirely). `availableStock` is null for anonymous users and an integer for authenticated customers. Apply `@inContext(preferredLocationId: ...)` on the operation to pin the customer's preferred location to the top of the result.

Locations (store picker UI)

OperationKindDescription
LocationsqueryPaginated list of active store locations (default 20, max 100). Filters: `near` (`{ latitude, longitude }`) for proximity search — sorts ascending by distance; `hasPickupEnabled` for pickup-only filtering; `locationType` (`RETAIL`, `WAREHOUSE`, `PICKUP_POINT`). When `near` is omitted, results are sorted by the merchant's `priority`, then name. Use for the BOPIS store picker UI. Public; no auth required.
LocationqueryFetches a single store location by `id` — full address, coordinates, business hours, pickup config (lead time, hours, timezone), and services. Returns null if the location is not found, not active, or owned by another shop. Use on the location detail page. Public; no auth required.

Treści cyfrowe

OperationKindDescription
ProductAttachmentsqueryPubliczne pliki dołączone do produktu — instrukcje, certyfikaty, karty gwarancyjne. Osobne zapytanie, a nie pole w podstawowym fragmencie produktu: załączniki wymagają dodatkowego odczytu po stronie serwera, więc lista produktów nie powinna za nie płacić. Pobierz je dopiero na karcie produktu.
OrderDigitalDownloadsqueryTreści cyfrowe kupione w zamówieniu, po opaque tokenie zamówienia (strona po-zakupowa gościa). Osobne zapytanie z tego samego powodu co wyżej — lista zamówień nie musi rozwiązywać pobrań dla każdej pozycji.

Forms engine (store-defined forms)

OperationKindDescription
RegistrationFormqueryRegistration form configuration of the store. Tells you whether new accounts need manual approval (`requireApproval` — `customerSignup` then returns accountStatus PENDING_APPROVAL and no token), which built-in sections to render (company / address / phone, each OFF / OPTIONAL / REQUIRED) and the store-defined custom fields. Collect custom-field values and pass them to `customerSignup.input.customFields`. All labels are resolved to the request language.
FormqueryA store-defined contact form by slug. Render `fields` and send the collected values via `formSubmit` with the same slug. Returns null when no active form exists under the slug — treat it as a 404 page state.
VariantPricesqueryBatch variant prices for the signed-in customer — the authenticated price channel. Use when the store restricts catalog prices to signed-in customers: `price` / `priceRange` / conversion fields come back null in the public catalog then, and price filtering / price sorting return the PRICE_FILTER_RESTRICTED error. Requires authentication on a price-restricted store (error code PRICES_REQUIRE_LOGIN otherwise); on an unrestricted store the query works for everyone. Max 100 ids per call; the response is never shared-cached.
ConfiguratorOptionPricesqueryConfigurator surcharges for the signed-in customer — the authenticated price channel for product configurator choices. Use when the store restricts catalog prices to signed-in customers: `ConfiguratorOption.surchargeAmount` / `surchargeType` come back null in the public catalog then. Options mapped to a stocked variant are priced via `VariantPrices` (they are real variants). Requires authentication on a price-restricted store (error code PRICES_REQUIRE_LOGIN otherwise); on an unrestricted store the query works for everyone. The response is never shared-cached.

Sklep

Konfiguracja sklepu (waluta, języki, branding, godziny otwarcia, dane kontaktowe, metody płatności, kraje wysyłki). Pobieraj raz na sesję i cache'uj — niemal wszystkie pozostałe zapytania są kontekstualizowane przez sklep zwrócony tutaj. SDK <StorefrontProvider> używa wewnętrznie ShopConfig do bootstrapu store'ów (currency, language, bot protection).

ShopqueryShop
query Shop

Returns shop configuration: name, base + supported currencies, supported locales, branding (logo, colors, fonts, social links), contact info, active payment methods, brand metadata, money format template, and the list of countries the shop ships to. Public; no auth required. Call once per session and cache — almost everything else is contextualized by the shop returned here.

GraphQL operation
query Shop {
shop {
...Shop
}
}
Uses fragments: Shop

shipsToCountries to kraje ze stref wysyłki sklepu — lista, z której budujesz wybór kraju dostawy. Kraje objęte sankcjami są z niej zawsze pominięte; szczegóły w Kody krajów.

Dla minimalnego payload pod provider — patrz ShopConfig. Refetchuj gdy merchant zmienia ustawienia waluty / języka albo gdy chcesz podchwycić nowe reguły bot-protection.

ShopConfigqueryShop
query ShopConfig

Minimal Shop payload for `<StorefrontProvider shopData={...}>` from `@doswiftly/storefront-sdk/react`. Returns exactly the fields the SDK's `ShopConfig` interface declares — currency setup (with `localeToCurrencyMap` for browser-locale-based currency detection), language setup, and bot protection. Cache for the session; refetch when the merchant updates currency / language settings or you want to pick up new bot-protection rules.

GraphQL operation
query ShopConfig {
shop {
...ShopConfigFields
}
}
Uses fragments: ShopConfigFields

Produkty

Pojedynczy produkt, paginowana lista, wyszukiwarka, autocomplete, konfigurator i filtry to fundament każdej witryny katalogowej. DoSwiftly zwraca produkt tylko jeśli jest storefront-accessible (status ACTIVE z visibility PUBLIC lub BUNDLE_ONLY) — produkty ukryte / draft nigdy nie wyciekają.

Pojedynczy produkt

Pobierz produkt po id LUB handle (URL-friendly slug). Wystarczy jeden z parametrów — jeśli oba podane, wygrywa ten przekazany.

ProductqueryProducts
query Product($id: ID, $handle: String)

Fetches a single product by `id` or `handle` (URL-friendly identifier). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
GraphQL operation
query Product($id: ID, $handle: String) {
product(id: $id, handle: $handle) {
...ProductFull
}
}
Uses fragments: ProductFull

Konfigurator produktu

Wariant Product zoptymalizowany pod UI konfiguratora — w jednym round-tripie pobiera produkt i jego pola konfiguratora przez configuratorFields (filledBy: CUSTOMER zwraca tylko pola edytowalne przez kupującego). Dzięki temu nie trzeba osobnego zapytania o konfigurator. Kompletny ekran krok po kroku: przepis Konfigurator produktu.

ProductConfiguratorqueryProducts
query ProductConfigurator($handle: String!, $filledBy: AttributeFillingMode = CUSTOMER)

Fetches a product together with its configurator fields, optimized for the product-page configurator UI. filledBy CUSTOMER returns only the fields a shopper edits; pass BOTH to also include seller-prefilled fields. Single round-trip.

Variables

NameTypeDefaultRequired
$handleString!Yes
$filledByAttributeFillingModeCUSTOMERNo
GraphQL operation
query ProductConfigurator($handle: String!, $filledBy: AttributeFillingMode = CUSTOMER) {
product(handle: $handle) {
...ProductFull
configuratorFields(filter: {filledBy: $filledBy}) {
...ConfiguratorField
}
}
}

Gdy sklep ogranicza widoczność cen (ceny po zalogowaniu), surchargeAmount w polach konfiguratora przychodzi jako null — tym zapytaniem dociągniesz dopłaty opcji po uwierzytelnieniu, bez ponownego pobierania całego konfiguratora (lustro VariantPrices dla wariantów; opcje z komponentem magazynowym wyceniasz właśnie przez VariantPrices — to realne warianty):

ConfiguratorOptionPricesqueryForms engine (store-defined forms)
query ConfiguratorOptionPrices($productId: ID!)

Configurator surcharges for the signed-in customer — the authenticated price channel for product configurator choices. Use when the store restricts catalog prices to signed-in customers: `ConfiguratorOption.surchargeAmount` / `surchargeType` come back null in the public catalog then. Options mapped to a stocked variant are priced via `VariantPrices` (they are real variants). Requires authentication on a price-restricted store (error code PRICES_REQUIRE_LOGIN otherwise); on an unrestricted store the query works for everyone. The response is never shared-cached.

Variables

NameTypeDefaultRequired
$productIdID!Yes
GraphQL operation
query ConfiguratorOptionPrices($productId: ID!) {
configuratorOptionPrices(productId: $productId) {
optionId
surchargeAmount
surchargeType
}
}

Paginowana lista produktów

Relay Connection (domyślnie 20, max 100). Obsługuje:

  • Strukturalne zapytanie query: "tag:summer AND variants.price:>10" (parser + free-text fallback po title / content)
  • Multi-filter logic: ten sam field name w filters[] wiele razy → OR; różne fieldy → AND
  • Sort keys: RELEVANCE (domyślny), TITLE, PRICE, CREATED_AT, UPDATED_AT; reverse: true odwraca kolejność. RELEVANCE porządkuje po trafności względem query — bez query nie ma czego rankować, więc lista wraca do najnowszych. Pozostałe klucze działają razem z query: wyszukiwanie zawęża zbiór, a wybrany klucz go porządkuje. BEST_SELLING, ID, PRODUCT_TYPE i VENDOR są zarezerwowane na przyszłość i dziś zachowują się jak CREATED_AT.
  • Faceted navigation: response zawiera blok filters z licznikami per filterable attribute value
ProductsqueryProducts
query Products($first: Int = 20, $after: String, $query: String, $sortKey: ProductSortKeys = RELEVANCE, $reverse: Boolean = false, $filters: [ProductFilter!])

Paginated product list (Relay Connection, default page size 20, max 100). The `query` argument supports a structured search syntax — `tag:summer`, `vendor:foo`, `product_type:shirts`, `variants.price:>10`, plus `AND`/`OR`/`NOT` — falling back to free-text title/content search. The `filters[]` array uses multi-filter logic: same field name appears multiple times → OR; different fields → AND. Sort: `RELEVANCE`, `TITLE`, `PRICE`, `NEWEST`, `OLDEST`, `BEST_SELLING`. The response includes a `filters` block for faceted navigation (counts per filterable attribute value).

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$queryStringNo
$sortKeyProductSortKeysRELEVANCENo
$reverseBooleanfalseNo
$filters[ProductFilter!]No
GraphQL operation
query Products($first: Int = 20, $after: String, $query: String, $sortKey: ProductSortKeys = RELEVANCE, $reverse: Boolean = false, $filters: [ProductFilter!]) {
products(
first: $first
after: $after
query: $query
sortKey: $sortKey
reverse: $reverse
filters: $filters
) {
edges {
node {
...ProductCard
}
cursor
}
nodes {
...ProductCard
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: PageInfo, ProductCard

Wyszukiwanie pełnotekstowe

Wariant Products zoptymalizowany pod search UI — wymaga $query jako pierwszej zmiennej, reszta args zachowuje semantykę.

ProductSearchqueryProducts
query ProductSearch($query: String!, $first: Int = 20, $after: String, $filters: [ProductFilter!])

Full-text product search — `$query` is required. Functionally equivalent to `Products` with `$query` set, minus the `sortKey` argument (search defaults to relevance ranking). Use for the search results page; combine with `filters[]` for guided refinement.

Variables

NameTypeDefaultRequired
$queryString!Yes
$firstInt20No
$afterStringNo
$filters[ProductFilter!]No
GraphQL operation
query ProductSearch($query: String!, $first: Int = 20, $after: String, $filters: [ProductFilter!]) {
products(query: $query, first: $first, after: $after, filters: $filters) {
edges {
node {
...ProductCard
}
cursor
}
nodes {
...ProductCard
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: PageInfo, ProductCard

Sugestie wyszukiwania (autocomplete)

Lekkie zapytanie pod search-as-you-type. Zwraca { products, queries, collections, categories } z dopasowaniami top-N — idealne do live autocomplete pod inputem szukajki.

SearchSuggestionsqueryProducts
query SearchSuggestions($query: String!, $limit: Int = 10)

Type-ahead suggestions for the storefront search input. Returns up to `$limit` matching products (hard cap 50) plus up to 5 styled query suggestions with `<mark>` tags around matched spans. Polish-language aware (handles morphology in suggestions). Run on each keystroke (debounce 200-300ms). The `$query` is capped at 100 characters server-side.

Variables

NameTypeDefaultRequired
$queryString!Yes
$limitInt10No
GraphQL operation
query SearchSuggestions($query: String!, $limit: Int = 10) {
searchSuggestions(query: $query, limit: $limit) {
products {
...ProductCard
}
queries {
text
styledText
}
}
}
Uses fragments: ProductCard

Filtry produktowe

Zwraca dostępne filtry dla bieżącego kontekstu (kolekcja, kategoria, search query): atrybuty filtrowalne z licznikami, zakres cenowy, kategorie, marki. Renderuje faceted sidebar — typowo wywoływane razem z Products (ten sam input).

ProductFiltersqueryAttribute Filters
query ProductFilters($input: AvailableFiltersInput)

Returns the dynamic facet filters available for a listing context — pass `collectionId`, `categoryId`, `searchQuery`, optional `available` (boolean for the availability facet), and optional `currentFilters` (array of attribute filters currently applied by the UI). For each visible & filterable attribute, returns either discrete value counts (for `SELECT` / `CHECKBOX` types) or numeric range bounds (for `SLIDER` types). Plus `priceRange`, `brands`, per-category counts, `activeCount` (length of `currentFilters`), `totalCount` (products in context — Relay-aligned), and `availableCount` (boolean facet count for `availableForSale`). All per-facet counts use exclude-self aggregation: a facet's count IGNORES its own currently-applied filter and APPLIES other filters — so the count reflects "products if this facet were toggled" rather than "products currently visible". Untracked inventory (gift cards, digital, made-to-order) is always counted as available. Use to render filter sidebars on listing/search pages.

Variables

NameTypeDefaultRequired
$inputAvailableFiltersInputNo
GraphQL operation
query ProductFilters($input: AvailableFiltersInput) {
productFilters(input: $input) {
...AvailableFilters
}
}
Uses fragments: AvailableFilters
Aggregacja atrybutów TEXT / TEXTAREA

filterValues jest dostępne także dla typów TEXT i TEXTAREA (nie tylko SELECT). Licznik productCount per unikalna wartość tekstowa używa indeksu GIN pg_trgm — możesz budować facet dla pola Producent / Materiał / Licencja bez konieczności konwersji atrybutu na SELECT.

Drill-into pojedynczego filtra

Drugi profil obok productFiltersproductFilters zwraca top-N facet'ów do quick browse w sidebar, attributeOptionsSearch służy do drill-into konkretnego filtra z autocomplete (np. „Pokaż wszystkie 832 marki" + search input). Honoruje kontekst kategorii / kolekcji / search query / currentFilters z exclude-self semantyką (gdy currentFilters zawiera ten sam atrybut, jest pomijany przy obliczaniu productCount).

attributeOptionsSearch istnieje w schema, ale nie jest pre-built operation w @doswiftly/storefront-operations — odpalaj jako ad-hoc query po stronie storefrontu:

query AttributeOptionsSearch($input: AttributeOptionsSearchInput!) {
attributeOptionsSearch(input: $input) {
edges {
cursor
node { id value label productCount swatch { colorHex image { url altText } } }
}
pageInfo { hasNextPage hasPreviousPage startCursor endCursor }
totalCount
}
}

Pełny zestaw typów filtrów i ich argumentów znajdziesz w referencji typów.

Ceny wariantów dla zalogowanych

Batchowe pobranie cen wariantów dla zalogowanego klienta — kanał cen po uwierzytelnieniu. Używaj, gdy sklep ogranicza ceny katalogu do zalogowanych klientów: pola price / priceRange i przeliczenia walutowe wracają wtedy w publicznym katalogu jako null, a filtrowanie i sortowanie po cenie kończy się błędem PRICE_FILTER_RESTRICTED. Na sklepie z ograniczeniem wymaga sesji klienta (bez niej kod błędu PRICES_REQUIRE_LOGIN); na sklepie bez ograniczenia działa dla każdego. Maksymalnie 100 identyfikatorów na wywołanie; odpowiedź nigdy nie trafia do współdzielonego cache.

VariantPricesqueryForms engine (store-defined forms)
query VariantPrices($variantIds: [ID!]!)

Batch variant prices for the signed-in customer — the authenticated price channel. Use when the store restricts catalog prices to signed-in customers: `price` / `priceRange` / conversion fields come back null in the public catalog then, and price filtering / price sorting return the PRICE_FILTER_RESTRICTED error. Requires authentication on a price-restricted store (error code PRICES_REQUIRE_LOGIN otherwise); on an unrestricted store the query works for everyone. Max 100 ids per call; the response is never shared-cached.

Variables

NameTypeDefaultRequired
$variantIds[ID!]!Yes
GraphQL operation
query VariantPrices($variantIds: [ID!]!) {
variantPrices(variantIds: $variantIds) {
variantId
price {
amount
currencyCode
}
compareAtPrice {
amount
currencyCode
}
}
}

Treść rich-text — argument format

Pola tekstowe redagowane w panelu (opisy produktów, kategorii, kolekcji, marek oraz treść wpisów blogowych i stron CMS) mają kanoniczne, strukturalne źródło. Storefront API renderuje je na żądanie do wybranej reprezentacji przez opcjonalny argument format: RichTextFormat:

WartośćCo zwracaKiedy używać
HTML (domyślna)Gotowy do renderu markup (bezpieczny podzbiór tagów)Wstawienie do strony przez dangerouslySetInnerHTML (owiń w sanitizeHtml z SDK)
TEXTCzysty tekst bez tagów<meta name="description">, podglądy, snippety, indeks wyszukiwarki
JSONStrukturalny dokument (string do sparsowania)Własny renderer (headless, aplikacja mobilna)

Argument jest opcjonalny — pominięcie zwraca HTML, więc istniejące zapytania działają bez zmian. Każda reprezentacja jest bezpieczna do renderu (sanityzacja XSS po stronie API).

Pola z argumentem format: Product.description, Category.description, Collection.description, Brand.description, BlogPost.content, ShopPage.body.

query ProductCopy($handle: String!) {
product(handle: $handle) {
description # HTML (domyślnie)
plain: description(format: TEXT) # czysty tekst — podglądy/snippety (do SEO użyj pól seo)
doc: description(format: JSON) # strukturalny dokument dla własnego renderera
}
}

Możesz zażądać kilku reprezentacji jednego pola w jednym zapytaniu, nadając im aliasy (plain, doc powyżej).

Do meta tagów ta konwersja nie jest potrzebna. seo jest gotowe do renderu: seo.title zwraca meta tytuł merchanta, a gdy pole zostało puste — nazwę zasobu; seo.description analogicznie meta opis, a w jego braku opis zasobu jako czysty tekst, przycięty na granicy słowa do długości pokazywanej w wynikach (strona CMS i wpis blogowy biorą najpierw zajawkę, dopiero potem treść). Renderujesz oba wprost, bez własnego fallbacku i bez format: TEXT.

Zwracamy ELEMENT, nie kompozycję: seo.title to sama nazwa zasobu, więc wzorzec ${seo.title} — ${shop.name}, separatory i numer strony zostają po Twojej stronie. Tag blogowy nie ma opisu, więc dostaje sam tytuł.

Wycofywane pola (usunięcie po 2026-09-02)

Zastąp starsze pola równoważnym format:

Wycofane poleZamiennik
Product.descriptionHtmldescription(format: HTML)
Collection.descriptionHtmldescription(format: HTML)
BlogPost.contentFormatformat wybierany per-request przez content(format: ...)

Pola nadal działają w okresie karencji, ale są oznaczone @deprecated — migruj przed datą usunięcia.


Kolekcje i kategorie

Kolekcje to kuratorskie grupy produktów (np. „Nowości", „Promocje", „Bestsellery"). Kategorie to hierarchiczne drzewo katalogu (np. „Buty → Sportowe → Trail running"). Oba mają handle (URL slug), a zarówno kolekcja, jak i kategoria dodatkowo wystawiają paginowaną listę swoich produktów inline.

Pojedyncza kolekcja z produktami

CollectionqueryCollections
query Collection($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsFilters: [ProductFilter!])

Fetches a single collection by `id` or `handle`, with paginated products. Collections come in two types: **MANUAL** (curated — products explicitly added by the merchant) and **AUTO** (rule-based — products matched dynamically). Both surfaces use the same field selection.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$productsFirstInt20No
$productsAfterStringNo
$productsFilters[ProductFilter!]No
GraphQL operation
query Collection($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsFilters: [ProductFilter!]) {
collection(id: $id, handle: $handle) {
...Collection
products(
first: $productsFirst
after: $productsAfter
filters: $productsFilters
) {
edges {
node {
...ProductCard
}
cursor
}
nodes {
...ProductCard
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: Collection, PageInfo, ProductCard

Lista kolekcji

CollectionsqueryCollections
query Collections($first: Int = 20, $after: String, $query: String, $sortKey: CollectionSortKeys = TITLE, $reverse: Boolean = false)

Paginated list of all active collections (default 20, max 100). Sort by `TITLE` or `UPDATED_AT` via `sortKey`. Note: the `query` argument is reserved for future text filtering — it is currently accepted but ignored.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$queryStringNo
$sortKeyCollectionSortKeysTITLENo
$reverseBooleanfalseNo
GraphQL operation
query Collections($first: Int = 20, $after: String, $query: String, $sortKey: CollectionSortKeys = TITLE, $reverse: Boolean = false) {
collections(
first: $first
after: $after
query: $query
sortKey: $sortKey
reverse: $reverse
) {
edges {
node {
...Collection
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: Collection, PageInfo

Pojedyncza kategoria

Zwraca kategorię z hierarchią — parent oraz lista children (rekurencyjny fragment buduje drzewo client-side). Pole products to paginowana lista produktów kategorii (Relay Connection) — sterujesz nią przez $productsSortKey / $productsFilters w jednym round-tripie, bez osobnego zapytania o produkty (analogicznie do kolekcji i marki). Jeśli zawężasz istniejącą listę produktów (np. ekran kategorii z facetami), użyj filtra products(filters: [{ category: { handle } }])handle jest stabilny w adresie URL, więc nie musisz wcześniej rozwiązywać go na id.

CategoryqueryCategories
query Category($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsSortKey: ProductSortKeys = BEST_SELLING, $productsFilters: [ProductFilter!])

Fetches a single category by `id` or `handle` with its parent, immediate children, and a paginated slice of its products. Use for category landing pages (hero + breadcrumbs + product grid in one round-trip) and sub-navigation. Nested `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns. Public — no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$productsFirstInt20No
$productsAfterStringNo
$productsSortKeyProductSortKeysBEST_SELLINGNo
$productsFilters[ProductFilter!]No
GraphQL operation
query Category($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsSortKey: ProductSortKeys = BEST_SELLING, $productsFilters: [ProductFilter!]) {
category(id: $id, handle: $handle) {
...Category
parent {
...Category
}
children {
...Category
}
products(
first: $productsFirst
after: $productsAfter
sortKey: $productsSortKey
filters: $productsFilters
) {
edges {
node {
...ProductCard
}
cursor
}
nodes {
...ProductCard
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: Category, PageInfo, ProductCard

Drzewo kategorii

Zwraca kategorie główne sklepu w jednym round-tripie z 2-3 poziomami zagnieżdżenia. Serwer batchuje odczyty (DataLoader) — brak N+1 niezależnie od głębokości drzewa.

CategoriesqueryCategories
query Categories

Returns active root categories for the shop. Each root exposes its `children` — build the tree client-side by walking those fields (server batches the lookups, no N+1). The hierarchy is not depth-capped server-side. Use for nav mega-menus and category pages.

GraphQL operation
query Categories {
categories(rootsOnly: true) {
nodes {
...Category
children {
...Category
children {
...Category
}
}
}
totalCount
}
}
Uses fragments: Category

Marki

Marka (producent / etykieta) to encja katalogu z własną stroną docelową — nazwą, logo, opisem (HTML) i metadanymi SEO. Marka ma handle (URL slug stabilny per sklep, np. ruta /brands/[handle]), a zapytanie brand dodatkowo wystawia paginowaną listę jej produktów inline — analogicznie do kolekcji.

Nie myl trzech różnych powierzchni „marki" w API — każda służy do czego innego:

PowierzchniaCo to jestKiedy używać
Encja Brand (ta sekcja)Strona marki pobierana po handle — nazwa, logo, opis, SEO + produkty markiRuta /brands/[handle], indeks marek, kafelek marki
Filtr ProductFilter.brandZawężenie listy produktów do marki (po handle lub id)Zawężanie wyników w products / Brand.products
Facet productFilters.brandsLista marek z licznikami produktów (BrandFilterValue) w bieżącym kontekścieSidebar nawigacji facetowej (checkboxy marek)

Krótko: encja = strona marki, filtr = zawężenie listy, facet = lista marek do wyboru w sidebarze. Facet i filtr opisuje SDK — Produkty.

Pojedyncza marka z produktami

Pobierz markę po id LUB handle (wystarczy jeden — jeśli oba podane, wygrywa id). Zwraca null, gdy marka nie istnieje lub została zarchiwizowana. Pole products to paginowana lista produktów marki (Relay Connection) — sterujesz nią przez $productsSortKey / $productsFilters w jednym round-tripie, bez osobnego zapytania o produkty.

BrandqueryBrands
query Brand($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsSortKey: ProductSortKeys = BEST_SELLING, $productsFilters: [ProductFilter!])

Fetches a single brand by `id` or `handle` (e.g. "funko" → /brands/funko) together with its landing-page fields (name, logo, description, SEO) and a paginated slice of its products. Use for brand pages. Returns null when the brand does not exist or is archived. Public — no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$productsFirstInt20No
$productsAfterStringNo
$productsSortKeyProductSortKeysBEST_SELLINGNo
$productsFilters[ProductFilter!]No
GraphQL operation
query Brand($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsSortKey: ProductSortKeys = BEST_SELLING, $productsFilters: [ProductFilter!]) {
brand(id: $id, handle: $handle) {
...Brand
products(
first: $productsFirst
after: $productsAfter
sortKey: $productsSortKey
filters: $productsFilters
) {
edges {
node {
...ProductCard
}
cursor
}
nodes {
...ProductCard
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: Brand, PageInfo, ProductCard

Lista marek

Paginowana lista aktywnych marek (indeks marek / nawigacja). Sortowanie przez sortKey: NAME (domyślny), PRODUCT_COUNT, CREATED_AT, UPDATED_AT; reverse: true odwraca kolejność. Opcjonalny query filtruje po nazwie marki.

BrandsqueryBrands
query Brands($first: Int = 20, $after: String, $query: String, $sortKey: BrandSortKeys = NAME, $reverse: Boolean = false)

Paginated list of active brands (brand index / navigation), default 20, max 100. Sort by `NAME` (default), `PRODUCT_COUNT`, `CREATED_AT` or `UPDATED_AT`; set `reverse: true` to descend. Optional `query` filters by brand name. Public — no auth required.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$queryStringNo
$sortKeyBrandSortKeysNAMENo
$reverseBooleanfalseNo
GraphQL operation
query Brands($first: Int = 20, $after: String, $query: String, $sortKey: BrandSortKeys = NAME, $reverse: Boolean = false) {
brands(
first: $first
after: $after
query: $query
sortKey: $sortKey
reverse: $reverse
) {
edges {
node {
...Brand
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: Brand, PageInfo

Koszyk

Koszyk to jedyny aggregate realizacji zamówienia — adres dostawy, metoda wysyłki, płatność, kody rabatowe, karty podarunkowe i finalizacja są wystawione bezpośrednio na obiekcie Cart. Nie ma osobnego obiektu Checkout. Mutacje koszyka opisane są na stronie Mutacje.

Pobranie koszyka

Cart jest re-fetchowany przy każdej zmianie (po mutacji koszyka SDK refetchuje automatycznie). Cart ID żyje w cookie cart-id (30 dni, SSR-visible) — patrz SDK — Koszyk.

CartqueryCart
query Cart($id: ID!)

Fetches a cart by `id` (the value persisted by the SDK in the `cart-id` cookie). The cart query is public — no auth needed to read it — but once a customer logs in and gets associated with the cart, mutations enforce ownership. Returns line items (paginated up to 100), totals, applied discount codes, gift cards, buyer identity, note, attributes, and warnings. Refetch after every cart mutation.

Variables

NameTypeDefaultRequired
$idID!Yes
GraphQL operation
query Cart($id: ID!) {
cart(id: $id) {
...Cart
}
}
Uses fragments: Cart

Walidacja kodu rabatowego (preview)

Walidacja kodu przed jego naliczeniem na koszyku — używaj na expand discount input żeby pokazać "Kod ważny: 10% rabatu" zanim user kliknie Apply. Mutacja cartDiscountCodesUpdate aplikuje kod realnie i zwraca user errors per cart-level rules.

Preview jest parytetowy z apply — nie kłamie. Kod scope-mismatch (ważny, ale żadna pozycja koszyka nie wchodzi w jego zasięg produktowy) zwróci isValid:false z error.code: NOT_APPLICABLE_TO_CART, dokładnie tak jak cartDiscountCodesUpdate ustawi dla niego isApplicable:false. Dzięki temu preview nie pokaże „Kod ważny", jeśli realne naliczenie dałoby 0 zł. Wynik zależy od cart.subtotal (reguły minimum-order) — nie cache'uj agresywnie: użyj fetchPolicy: "network-only" albo dołącz cart.subtotal do klucza cache.

CartValidateDiscountCodequeryDiscount Code Validation
query CartValidateDiscountCode($cartId: ID!, $discountCode: String!)

Read-only validation of a discount code against an existing cart — does NOT modify cart state. Returns `{ isValid, discount, error }` (`DiscountValidationResult`) for previewing the effect of a code (inline UI feedback as the user types, before they commit to applying via `cartDiscountCodesUpdate`). Validates: discount existence + active status + customer eligibility + minimum order amount + minimum quantity met. Errors: `NOT_FOUND`, `INACTIVE`, `NOT_STARTED`, `EXPIRED`, `USAGE_LIMIT_REACHED`, `CUSTOMER_USAGE_LIMIT_REACHED`, `CUSTOMER_NOT_ELIGIBLE`, `MINIMUM_ORDER_NOT_MET`, `MINIMUM_QUANTITY_NOT_MET`.

Variables

NameTypeDefaultRequired
$cartIdID!Yes
$discountCodeString!Yes
GraphQL operation
query CartValidateDiscountCode($cartId: ID!, $discountCode: String!) {
cartValidateDiscountCode(cartId: $cartId, discountCode: $discountCode) {
isValid
discount {
code
title
type
value
discountAmount {
amount
currencyCode
}
}
error {
code
message
}
}
}

Dostępne metody płatności

Lista metod płatności dostępnych dla sklepu (PayU, Przelewy24, BLIK, Stripe, Apple Pay, COD itd.) — używana w checkout payment step.

AvailablePaymentMethodsqueryPayment Methods
query AvailablePaymentMethods

Returns the active payment methods for the shop, sorted by the merchant-configured display position. Shop-level — does NOT vary by cart amount or currency. Each method exposes `type` (`CARD`, `BANK_TRANSFER`, `BLIK`, `PAYPAL`, `APPLE_PAY`, `GOOGLE_PAY`, `CASH_ON_DELIVERY`, `OTHER`), provider, icon, description, and supported currencies. Use to render the payment step of checkout.

GraphQL operation
query AvailablePaymentMethods {
availablePaymentMethods {
...AvailablePaymentMethods
}
}
Uses fragments: AvailablePaymentMethods

Dostępne metody płatności — cart-aware (checkout flow)

Ta sama lista metod, ale w kontekście konkretnego koszyka: opłaty za formy płatności (np. za pobranie) mają tu gotowe kwoty policzone od wartości tego koszyka — dokładnie te same, które trafią do podsumowania po wyborze. Kafelek metody i podsumowanie czytają to samo pole, więc kwoty nigdy się nie rozjadą.

Używaj w kroku płatności kasy, od momentu utworzenia koszyka. Dla podglądów poza koszykiem (np. siatka form płatności na stronie produktu) służy shop-level operacja powyżej — tam fee jest zawsze null, bo kwota dopłaty nie istnieje bez koszyka. Pełny scenariusz: przepis Koszt formy płatności na kafelku.

CartAvailablePaymentMethodsqueryPayment Methods
query CartAvailablePaymentMethods($cartId: ID!)

Cart-aware payment methods discovery. Returns the same active payment methods as the shop-level `availablePaymentMethods`, but with surcharge amounts resolved: a payment fee can be a percentage of the order value, so the exact amount (e.g. "+5 zł" or "+2.5% (7.18 zł)") is only computable against a cart. Prefer this once a cart exists (`cartCreate`); use the shop-level query for pre-cart previews (method grid, product page upsell) — there `fee` is always null, because the amount it would carry does not exist without a cart. Read `methods[].fee` for the whole-tile surcharge; when instruments carry different fees (e.g. per-brand card surcharges), read `methods[].instruments[].fee` per instrument instead. This query does NOT change cart state and is safe to retry; returns null when the cart does not exist.

Variables

NameTypeDefaultRequired
$cartIdID!Yes
GraphQL operation
query CartAvailablePaymentMethods($cartId: ID!) {
cart(id: $cartId) {
id
availablePaymentMethods {
...PaymentMethod
}
}
}
Uses fragments: PaymentMethod

Dostępne metody wysyłki — preview (pre-cart)

Używaj tylko gdy klient jeszcze nie utworzył koszyka — np. shipping calculator na product detail page („ile zapłacę za dostawę?"). Po utworzeniu cart preferuj cart-aware wariant poniżej (eliminuje konieczność client-side computation subtotal/totalWeight i automatycznie respektuje digital-only constraint).

AvailableShippingMethodsqueryShipping Methods
query AvailableShippingMethods($address: ShippingAddressInput!, $cart: CartShippingInput)

Returns shipping methods for a given destination address and cart shape (subtotal, total weight, currency). The query computes everything from the inputs alone — no existing cart is required, so it can be used for "shipping cost preview" UIs (e.g. product detail page shipping calculator) before the customer adds anything to a cart. Each method includes price, free-shipping progress (`{ qualifies, currentAmount, threshold, remaining, progressPercent }`), estimated delivery, and carrier metadata. Sorted by the merchant's `sortOrder`, then by price. For a cart-bound checkout flow (where the cart is already known and the storefront wants the resolver to skip non-physical items and surface a `DIGITAL_ONLY_NO_SHIPPING` user error for all-digital carts), use `CartAvailableShippingMethods` against `cart.availableShippingMethods(address)` instead.

Variables

NameTypeDefaultRequired
$addressShippingAddressInput!Yes
$cartCartShippingInputNo
GraphQL operation
query AvailableShippingMethods($address: ShippingAddressInput!, $cart: CartShippingInput) {
availableShippingMethods(address: $address, cart: $cart) {
methods {
...AvailableShippingMethod
}
freeShippingProgress {
...FreeShippingProgress
}
userErrors {
...UserError
}
}
}

Dostępne metody wysyłki — cart-aware (checkout flow)

Field na Cart aggregate. Backend pobiera dane koszyka z DB (subtotal, totalWeight, productType per linia), więc nie musisz ich obliczać po stronie klienta. Dla koszyka 100% cyfrowego (typy DIGITAL / GIFT_CARD / SERVICE / SUBSCRIPTION) zwraca empty methods + userErrors[{ code: 'DIGITAL_ONLY_NO_SHIPPING' }] — możesz użyć tego sygnału do pominięcia całego kroku wyboru wysyłki w checkout.

Razem z polem cart.requiresShipping: Boolean! (single bool) daje storefrontowi spójny mechanizm decydowania kiedy renderować shipping picker.

CartAvailableShippingMethodsqueryShipping Methods
query CartAvailableShippingMethods($cartId: ID!, $address: ShippingAddressInput!)

Cart-aware shipping methods discovery. Returns shipping methods available for the cart's contents at the given destination, with subtotal and physical-item weight pulled from the cart aggregate (no need to compute them client-side). When the cart contains only non-physical items (digital, gift card, service, subscription), the response is `methods: []` plus a `DIGITAL_ONLY_NO_SHIPPING` user error — use this as the signal to skip rendering the shipping picker step. Prefer this query over the standalone `AvailableShippingMethods` once a cart has been created (`cartCreate`). For pre-cart "shipping cost preview" UIs on product detail pages, the standalone query remains the right tool.

Variables

NameTypeDefaultRequired
$cartIdID!Yes
$addressShippingAddressInput!Yes
GraphQL operation
query CartAvailableShippingMethods($cartId: ID!, $address: ShippingAddressInput!) {
cart(id: $cartId) {
id
requiresShipping
availableShippingMethods(address: $address) {
methods {
...AvailableShippingMethod
}
freeShippingProgress {
...FreeShippingProgress
}
userErrors {
...UserError
}
}
}
}

Live carrier rates (opcjonalne)

Pobiera stawki wysyłki w czasie rzeczywistym od skonfigurowanych dostawców (InPost, DPD, Furgonetka itp.). Wyniki cachowane w Redis przez 15 minut na kombinację adresu i wagi. Dostawcy nieodpowiadający w czasie / zwracający błąd są pomijani. Query istnieje w schema, ale nie jest pre-built operation — odpalaj ad-hoc:

query AvailableShippingRates(
$address: ShippingAddressInput!
$packages: [PackageDimensionsInput!]
$totalWeight: Float
) {
availableShippingRates(address: $address, packages: $packages, totalWeight: $totalWeight) {
rates { providerId serviceId serviceName price { amount currencyCode } estimatedDeliveryDays isPickupAvailable isCashOnDeliveryAvailable }
errors { provider message code }
cached
}
}

Klient

Profil klienta z adresami i historią zamówień. SDK <StorefrontProvider> automatycznie dołącza nagłówek Authorization: Bearer <customerAccessToken> po customerLogin, więc te zapytania działają bez ręcznego przekazywania tokenu.

Formularz rejestracji (konfiguracja pól)

Publiczna konfiguracja formularza rejestracji sklepu — renderuj formularz zapisu na jej podstawie zamiast hardkodować pola. Mówi, czy nowe konta wymagają ręcznej akceptacji (requireApprovalcustomerSignup zwraca wtedy accountStatus: PENDING_APPROVAL i nie wydaje tokenu), które wbudowane sekcje pokazać (firma / adres / telefon, każda w trybie OFF / OPTIONAL / REQUIRED) oraz pola własne zdefiniowane przez sklep. Wartości pól własnych przekaż do customerSignup.input.customFields. Etykiety przychodzą w języku żądania.

RegistrationFormqueryForms engine (store-defined forms)
query RegistrationForm

Registration form configuration of the store. Tells you whether new accounts need manual approval (`requireApproval` — `customerSignup` then returns accountStatus PENDING_APPROVAL and no token), which built-in sections to render (company / address / phone, each OFF / OPTIONAL / REQUIRED) and the store-defined custom fields. Collect custom-field values and pass them to `customerSignup.input.customFields`. All labels are resolved to the request language.

GraphQL operation
query RegistrationForm {
registrationForm {
requireApproval
companySection
addressSection
phoneSection
fields {
...FormField
}
}
}
Uses fragments: FormField

Pełny profil (z adresami i historią zamówień)

Zwraca profil klienta z paginowanymi adresami (Relay Connection) i historią zamówień. Field numberOfOrders jest typu UnsignedInt64 (zwracany jako String) — bezpieczny dla dużych wartości.

CustomerqueryCustomer (requires auth)
query Customer

Full customer profile — basic info plus the first 10 addresses and first 10 orders. Heaviest customer query; for narrow use cases prefer `CustomerProfile` (no orders / addresses) or `CustomerOrder` (single order). Returns null if unauthenticated.

GraphQL operation
query Customer {
customer {
...Customer
addresses(first: 10) {
edges {
cursor
node {
...MailingAddress
}
}
nodes {
...MailingAddress
}
pageInfo {
...PageInfo
}
totalCount
}
orders(first: 10) {
edges {
node {
...Order
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
}

Lekki profil (bez adresów / zamówień)

Wariant pod stronę ustawień / profilu — szybsze niż Customer bo pomija historię zamówień i listę adresów. Używaj na /account jeśli nie potrzebujesz orders.

CustomerProfilequeryCustomer (requires auth)
query CustomerProfile

Lightweight customer profile (no orders, no addresses list). Use for settings / profile pages that only need basic customer info — much cheaper than `Customer`. Returns null if unauthenticated.

GraphQL operation
query CustomerProfile {
customer {
...Customer
}
}
Uses fragments: Customer

Adresy klienta (paginowane)

Dedykowane zapytanie tylko o adresy z paginacją — używaj na stronie zarządzania adresami dostawy.

CustomerAddressesqueryCustomer (requires auth)
query CustomerAddresses

Authenticated customer's saved address book — used on checkout to let the buyer pick a previously-used shipping / billing address instead of typing it. Each entry carries B2B invoicing fields (`taxId`, `vatNumber`) and the `isDefault` flag so the same list serves both as the shipping picker and as the billing/invoice picker. Returns up to 50 addresses (Relay Connection — buyers rarely keep more); for the unauthenticated case the connection is empty (no error). The default address is also surfaced as `Customer.defaultAddress`.

GraphQL operation
query CustomerAddresses {
customer {
addresses(first: 50) {
nodes {
...MailingAddress
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: MailingAddress, PageInfo

Pojedyncze zamówienie klienta

Szczegóły jednego zamówienia. Bardziej wydajne niż pobieranie pełnego profilu z Customer — używaj na /account/orders/:id.

CustomerOrderqueryCustomer (requires auth)
query CustomerOrder($orderId: ID!)

Single order by `orderId`. Returns only orders that belong to the authenticated customer (cross-customer access returns null, not an error). Much cheaper than fetching the full `Customer` payload to access one order. Use on the order detail page.

Variables

NameTypeDefaultRequired
$orderIdID!Yes
GraphQL operation
query CustomerOrder($orderId: ID!) {
customerOrder(orderId: $orderId) {
...Order
}
}
Uses fragments: Order

Zamówienia (dostęp gościa)

Klient gość — bez konta — nie ma customerAccessToken, ale otrzymuje opaque Order.accessToken w payload'zie cartComplete. To umożliwia mu wejście na /orders/confirmation?token=... z pełnym widokiem zamówienia.

Order by opaque token

Dostęp gościa do podsumowania zamówienia bez sesji. Przeznaczone do strony potwierdzenia tuż po cartComplete. Opcjonalny email to mechanizm defense-in-depth (przy niezgodności query zwraca null).

OrderByTokenqueryCustomer (requires auth)
query OrderByToken($token: String!, $email: String)

Fetch a single order using its opaque access token (`Order.accessToken`) — designed for guest order summary pages where the buyer has not signed in. The token is returned in `cartComplete.order.accessToken` immediately after checkout completes; persist it in an HTTP-only cookie (preferred) or `sessionStorage` for the post-checkout page (NEVER `localStorage`). Optional `email` parameter adds defense-in-depth: when provided, it is matched case-insensitively against the order's buyer email; on mismatch the query returns `null` exactly like an invalid token (the response shape is identical, so an attacker cannot distinguish "token valid, wrong email" from "token invalid"). Rate-limited to 5 requests per minute per IP+shop combination to deter token enumeration; clients exceeding the limit receive a GraphQL error with `extensions.code: THROTTLED`. The response is marked `Cache-Control: no-store` so per-customer order data is never served from CDN or browser cache between users. Safe to retry; the token is permanent until the order is deleted.

Variables

NameTypeDefaultRequired
$tokenString!Yes
$emailStringNo
GraphQL operation
query OrderByToken($token: String!, $email: String) {
orderByToken(token: $token, email: $email) {
...Order
}
}
Uses fragments: Order
Bezpieczeństwo i caching
  • Zapytanie jest publiczne (nie wymaga sesji ani tokenu klienta)
  • Rate limit: 5 żądań / minutę / IP + sklep
  • Odpowiedź nosi nagłówek Cache-Control: no-store — nie cache'uj jej na CDN
  • Order.accessToken (UUID v4, trwały per zamówienie) zwracany w cartComplete.order natychmiast po finalizacji
  • Storefront powinien przechowywać token w HTTP-only cookie lub sessionStoragenigdy w localStorage

Pełny przewodnik: SDK — Zamówienia.


Przesyłki i zwroty

Po cartComplete zamówienie ma jeden lub więcej Shipment (paczek u kuriera) i opcjonalnie Return (RMA — zwrot zainicjowany przez klienta).

Pojedyncza przesyłka

ShipmentqueryShipments / Tracking
query Shipment($id: ID!)

Fetches a shipment by `id` with status, tracking events, recipient address, and shipped/delivered timestamps. **Auth required** — customer access token plus ownership of the parent order. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch to prevent enumeration), `FETCH_FAILED`.

Variables

NameTypeDefaultRequired
$idID!Yes
GraphQL operation
query Shipment($id: ID!) {
shipment(id: $id) {
shipment {
...Shipment
}
userErrors {
...UserError
}
}
}
Uses fragments: Shipment, UserError

Tracking przesyłki po numerze przewozowym

Lekkie publiczne zapytanie dla strony „Track your shipment" — pozwala znaleźć status bez logowania.

ShipmentByTrackingNumberqueryShipments / Tracking
query ShipmentByTrackingNumber($trackingNumber: String!)

**Public** shipment lookup by carrier tracking number — no auth required. Designed for "Track my order" landing pages reachable without login. Returns the basic shipment fragment including recipient address. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_INPUT`, `NOT_FOUND`, `FETCH_FAILED`.

Variables

NameTypeDefaultRequired
$trackingNumberString!Yes
GraphQL operation
query ShipmentByTrackingNumber($trackingNumber: String!) {
shipmentByTrackingNumber(trackingNumber: $trackingNumber) {
shipment {
...ShipmentBasic
}
userErrors {
...UserError
}
}
}
Uses fragments: ShipmentBasic, UserError

Pojedynczy zwrot (RMA)

ReturnqueryReturns / RMA
query Return($id: ID!)

Fetches a single return (RMA) by `id` with line items, refund/compensation info, and history. **Auth required** — customer access token plus ownership of the return. Wrapped response: `{ return, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch), `FETCH_FAILED`.

Variables

NameTypeDefaultRequired
$idID!Yes
GraphQL operation
query Return($id: ID!) {
return(id: $id) {
return {
...Return
}
userErrors {
...UserError
}
}
}
Uses fragments: Return, UserError

Zwroty per zamówienie

ReturnsByOrderqueryReturns / RMA
query ReturnsByOrder($orderId: ID!)

Lists returns for a given order (paginated, default page size 20, cursor-based). **Auth required** — customer access token plus ownership of the order; the connection is empty (no explicit error) on auth failure. Use on the order detail page to show return history.

Variables

NameTypeDefaultRequired
$orderIdID!Yes
GraphQL operation
query ReturnsByOrder($orderId: ID!) {
returnsByOrder(orderId: $orderId) {
edges {
node {
...Return
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: PageInfo, Return

Powody zwrotu (do formularza RMA)

Statyczna lista enum'ów wystawiana w formularzu „Zwracam, bo..." — pre-fetchnij raz na sesję.

ReturnReasonsqueryReturns / RMA
query ReturnReasons

Returns the standard list of return reasons used by the RMA flow: `DEFECTIVE`, `NOT_AS_DESCRIBED`, `WRONG_ITEM`, `CHANGED_MIND`, `BETTER_PRICE`, `DAMAGED_SHIPPING`, `OTHER`. The list is fixed across all shops — not per-shop configurable. Public; no auth required.

GraphQL operation
query ReturnReasons {
returnReasons {
...ReturnReasonOption
}
}
Uses fragments: ReturnReasonOption

Karty podarunkowe (Gift cards)

Gift card to balance-bearing token — klient kupuje kartę za X PLN, otrzymuje kod, ktoś inny realizuje w checkout. DoSwiftly wspiera digital gift cards (kod email) i fizyczne (kod w pudełku).

Sprawdzenie karty (full payload)

Zwraca pełne dane karty po kodzie — balance, expiry, status (active / depleted / expired / cancelled).

GiftCardqueryGift Cards
query GiftCard($code: String!)

Public gift-card lookup by `code`. Returns balance, currency, expiry, and `maskedCode` (first 4 + last 4 chars only — the full code never leaks back). Returns null if the code is unknown (rather than an explicit error, to limit enumeration). **Rate-limited**: 10 requests per 60 seconds per IP.

Variables

NameTypeDefaultRequired
$codeString!Yes
GraphQL operation
query GiftCard($code: String!) {
giftCard(code: $code) {
...GiftCard
}
}
Uses fragments: GiftCard

Walidacja przed użyciem

Lekka walidacja w checkout — sprawdza czy kod istnieje, czy nie wygasł i czy ma wystarczający balance dla $amount. Mutacja cartApplyGiftCard aplikuje kartę realnie.

GiftCardValidatequeryGift Cards
query GiftCardValidate($code: String!, $amount: Float)

Validates whether a gift card is usable (and optionally for a given `$amount`). Checks status (`DISABLED`, `USED`, `EXPIRED`), expiry date, and — when `$amount` is provided — sufficient balance. Returns `{ validation: { isValid, availableBalance, error: { code, message } }, userErrors[] }`. Validation error codes: `NOT_FOUND`, `DISABLED`, `ALREADY_USED`, `EXPIRED`, `INSUFFICIENT_BALANCE`. **Rate-limited**: 10 / 60s.

Variables

NameTypeDefaultRequired
$codeString!Yes
$amountFloatNo
GraphQL operation
query GiftCardValidate($code: String!, $amount: Float) {
giftCardValidate(code: $code, amount: $amount) {
validation {
...GiftCardValidation
}
userErrors {
...UserError
}
}
}
Uses fragments: GiftCardValidation, UserError

Program lojalnościowy

Loyalty program oparty o punkty + tiery (Bronze / Silver / Gold / Platinum). Klient zarabia punkty za zamówienia (× tier multiplier) i wymienia je na nagrody (rewards). Większość zapytań wymaga autoryzacji klienta (Authorization: Bearer <token>).

Status członkostwa klienta

Punkty, tier, postęp do następnego, suma rocznych wydatków, ostatnia aktywność.

LoyaltyMemberqueryLoyalty Program
query LoyaltyMember

Returns the logged-in customer's loyalty membership: points (current, pending, redeemed, expired, expiring), current tier, tier progress, annual spend, last activity. Returns null if the customer is not enrolled — there is **no auto-enrollment** here (enrollment happens via signup or a first qualifying order). Auth required.

GraphQL operation
query LoyaltyMember {
loyaltyMember {
...LoyaltyMember
}
}
Uses fragments: LoyaltyMember

Definicje tierów

Publiczna lista tierów — możesz pokazać na stronie programu „Jak działa nasz program" bez logowania.

LoyaltyTiersqueryLoyalty Program
query LoyaltyTiers

Lists the loyalty tiers configured for the shop (`BRONZE`, `SILVER`, `GOLD`, `PLATINUM`, `DIAMOND` etc.) with their `minPoints`, `minAnnualSpend`, `pointsMultiplier`, and custom benefits. Sorted by `minPoints` ASC. Public; no auth required.

GraphQL operation
query LoyaltyTiers {
loyaltyTiers {
...LoyaltyTier
}
}
Uses fragments: LoyaltyTier

Katalog nagród

Lista dostępnych rewards do wymiany za punkty (rabaty %, kwoty, produkty, freebies).

LoyaltyRewardsqueryLoyalty Program
query LoyaltyRewards

Lists rewards customers can redeem (free shipping, percent off, free product, gift card). Filtered to **active** rewards only (`is_active = true` AND inside their `starts_at`/`ends_at` window). Public; no auth required.

GraphQL operation
query LoyaltyRewards {
loyaltyRewards {
...LoyaltyReward
}
}
Uses fragments: LoyaltyReward

Historia transakcji punktowych

Paginowana lista zdarzeń EARNED / REDEEMED / EXPIRED / ADJUSTED z opisem i orderId.

LoyaltyTransactionsqueryLoyalty Program
query LoyaltyTransactions($first: Int = 20, $after: String)

Paginated history of loyalty point transactions for the logged-in customer (default 20). Transaction `type` enum: `EARN_PURCHASE`, `EARN_SIGNUP`, `EARN_REFERRAL`, `EARN_REVIEW`, `EARN_BIRTHDAY`, `EARN_BONUS`, `REDEEM`, `EXPIRE`, `ADJUST`, `REFUND_REVERSAL`. Auth required — empty connection if unauthenticated.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
GraphQL operation
query LoyaltyTransactions($first: Int = 20, $after: String) {
loyaltyTransactions(first: $first, after: $after) {
edges {
node {
...LoyaltyTransaction
}
cursor
}
pageInfo {
...LoyaltyPageInfo
}
totalCount
}
}

Publiczna konfiguracja programu

Włączony / wyłączony, nazwa punktów, multiplier per PLN, expiry policy, dostępne actions, referral settings. Pre-fetchnij na bootstrap żeby zdecydować czy renderować loyalty UI w ogóle.

LoyaltySettingsqueryLoyalty Program
query LoyaltySettings

Returns the loyalty program configuration: `isEnabled`, `pointsName` (e.g. "stars"), `pointsPerCurrency`, `pointsExpiryMonths`, available earn actions, referral settings. Use this at app boot to decide whether to render any loyalty UI at all. Public; no auth required.

GraphQL operation
query LoyaltySettings {
loyaltySettings {
...LoyaltySettings
}
}
Uses fragments: LoyaltySettings

Estymacja punktów dla zamówienia

Pre-checkout preview „zarobisz X punktów za to zamówienie" — uwzględnia mnożnik tieru klienta.

EstimatePointsqueryLoyalty Program
query EstimatePoints($orderTotal: Float!)

Estimates how many loyalty points the customer would earn for an order of `$orderTotal` (in major currency units). When the customer is authenticated, the result accounts for their current tier's points multiplier. Use on cart/checkout to show "Earn X points with this order".

Variables

NameTypeDefaultRequired
$orderTotalFloat!Yes
GraphQL operation
query EstimatePoints($orderTotal: Float!) {
estimatePoints(orderTotal: $orderTotal) {
...PointsEstimate
}
}
Uses fragments: PointsEstimate

Statystyki poleceń (referrals)

Kod polecający klienta + URL do udostępniania + liczniki polecień (total / completed / pending) + zarobione punkty.

ReferralStatsqueryLoyalty Program
query ReferralStats

Returns the customer's referral statistics: `referralCode`, `shareUrl`, `totalReferred`, `completedReferrals`, `pendingReferrals`, `totalPointsEarned`. Auth required. Returns null if unauthenticated or if the referral program is disabled for the shop.

GraphQL operation
query ReferralStats {
referralStats {
...ReferralStats
}
}
Uses fragments: ReferralStats

Newsletter

Zachęta za zapis (baner rabatowy)

Publiczna konfiguracja zachęty „zapisz się do newslettera i odbierz kod rabatowy" — isEnabled plus kształt nagrody (typ, procent lub kwota, minimalna wartość zamówienia, dni ważności kodu). Sklep bez włączonej kampanii zwraca bezpieczny payload z isEnabled: false (nie null) — renderuj baner warunkowo. Wartości pochodzą wprost z rabatu skonfigurowanego przez merchanta, więc treść banera zawsze zgadza się z kodem, który klient dostanie mailem po potwierdzeniu zapisu (mutacje zapisu: Newsletter).

NewsletterIncentivequeryLoyalty Program
query NewsletterIncentive

Returns the shop's newsletter signup incentive — when `isEnabled` is true, render the signup banner with the returned discount shape (e.g. "subscribe & get -10%"); a confirmed signup earns a personal, single-use code delivered by email (it works only for the address it was issued to). When false, hide the incentive messaging — plain newsletter signup still works. Public; no auth required.

GraphQL operation
query NewsletterIncentive {
newsletterIncentive {
...NewsletterIncentive
}
}
Uses fragments: NewsletterIncentive

Formularze sklepu

Formularz zdefiniowany przez sklep (po slugu)

Formularz (np. kontaktowy) zdefiniowany przez merchanta w panelu. Renderuj fields (klucz, typ, etykieta, opcje, wymagalność, kolejność), a zebrane wartości wyślij mutacją formSubmit z tym samym slugiem. null oznacza, że pod slugiem nie ma aktywnego formularza — potraktuj to jak stan strony 404.

FormqueryForms engine (store-defined forms)
query Form($slug: String!)

A store-defined contact form by slug. Render `fields` and send the collected values via `formSubmit` with the same slug. Returns null when no active form exists under the slug — treat it as a 404 page state.

Variables

NameTypeDefaultRequired
$slugString!Yes
GraphQL operation
query Form($slug: String!) {
form(slug: $slug) {
id
slug
name
fields {
...FormField
}
}
}
Uses fragments: FormField

Recenzje

Recenzje produktów (rating 1-5 gwiazdek + komentarz + helpful votes). Moderowane po stronie merchanta — productReviews zwraca tylko zatwierdzone.

Recenzje produktu (paginowane)

ProductReviewsqueryReviews
query ProductReviews($productId: ID!, $first: Int = 10, $after: String, $sortKey: ReviewSortKey = CREATED_AT, $reverse: Boolean = true)

Paginated list of customer reviews for a product, **filtered to APPROVED reviews only** (PENDING / REJECTED reviews are not exposed to the storefront). Sort by `CREATED_AT` (default), helpfulness, or rating. Public; no auth required.

Variables

NameTypeDefaultRequired
$productIdID!Yes
$firstInt10No
$afterStringNo
$sortKeyReviewSortKeyCREATED_ATNo
$reverseBooleantrueNo
GraphQL operation
query ProductReviews($productId: ID!, $first: Int = 10, $after: String, $sortKey: ReviewSortKey = CREATED_AT, $reverse: Boolean = true) {
productReviews(
productId: $productId
first: $first
after: $after
sortKey: $sortKey
reverse: $reverse
) {
edges {
node {
...ProductReview
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: PageInfo, ProductReview

Agregaty (rating distribution)

Średnia ocen, count per gwiazdkę, total reviews — pod widget „4.8 ★ (132 reviews)" na product detail.

ReviewStatsqueryReviews
query ReviewStats($productId: ID!)

Aggregate review statistics for a product: average rating, total count, distribution per star (1-5). Computed from APPROVED reviews only. Use for product card review summaries. Public; no auth required.

Variables

NameTypeDefaultRequired
$productIdID!Yes
GraphQL operation
query ReviewStats($productId: ID!) {
reviewStats(productId: $productId) {
...ReviewStats
}
}
Uses fragments: ReviewStats

Lista życzeń (Wishlist)

Klient może mieć wiele list życzeń (jedna domyślna „Moje ulubione" + custom np. „Prezenty na święta"). Items to powiązania z productVariantId + opcjonalnym note.

Listy klienta (paginowane)

WishlistsqueryWishlists
query Wishlists($first: Int = 20, $after: String)

Paginated list of the logged-in customer's wishlists (default 20). Auth required — empty connection if unauthenticated. Customers typically have a small set (<10).

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
GraphQL operation
query Wishlists($first: Int = 20, $after: String) {
wishlists(first: $first, after: $after) {
edges {
cursor
node {
...Wishlist
}
}
nodes {
...Wishlist
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
totalCount
}
}
Uses fragments: Wishlist

Pojedyncza lista z itemami

WishlistByIdqueryWishlists
query WishlistById($id: ID!)

Fetches a single wishlist by `id`. Private wishlists are visible only to the owner; public wishlists are visible to anyone. Note: this query supports lookup by `id` only — there is currently no way to fetch a wishlist by its share token.

Variables

NameTypeDefaultRequired
$idID!Yes
GraphQL operation
query WishlistById($id: ID!) {
wishlist(id: $id) {
...Wishlist
}
}
Uses fragments: Wishlist

Blog (content marketing)

Blog DoSwiftly to standardowy CMS pod treści marketingowe — posty, kategorie, tagi, featured flag. Do wpisu, kategorii i tagu merchant może dodatkowo przypiąć produkty (merchandising), które renderujesz jako pasek przy treści.

Lista postów (z filtrowaniem i sortowaniem)

BlogPostsqueryBlog
query BlogPosts($first: Int = 20, $after: String, $categoryHandle: String, $tagHandle: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false)

Paginated list of published blog posts. Filter by `categoryHandle`, `tagHandle`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$categoryHandleStringNo
$tagHandleStringNo
$featuredBooleanNo
$sortKeyBlogPostSortKeyPUBLISHED_ATNo
$reverseBooleanfalseNo
GraphQL operation
query BlogPosts($first: Int = 20, $after: String, $categoryHandle: String, $tagHandle: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
blogPosts(
first: $first
after: $after
categoryHandle: $categoryHandle
tagHandle: $tagHandle
featured: $featured
sortKey: $sortKey
reverse: $reverse
) {
edges {
node {
...BlogPost
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: BlogPost, PageInfo

Pojedynczy post

Po id lub handle.

BlogPostqueryBlog
query BlogPost($id: ID, $handle: String)

Fetches a single blog post by `id` or `handle`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
GraphQL operation
query BlogPost($id: ID, $handle: String) {
blogPost(id: $id, handle: $handle) {
...BlogPost
}
}
Uses fragments: BlogPost

Kategorie blogowe

Lista wszystkich kategorii (nawigacja bloga):

BlogCategoriesqueryBlog
query BlogCategories

Lists all blog categories with per-category `postCount` and SEO metadata. Use to render category navigation on blog pages. Public; no auth required.

GraphQL operation
query BlogCategories {
blogCategories {
...BlogCategory
}
}
Uses fragments: BlogCategory

Pojedyncza kategoria po id lub handle — na stronę kategorii (obraz + seo). Listę wpisów w kategorii pobierasz osobno przez BlogPosts z argumentem categoryHandle.

BlogCategoryqueryBlog
query BlogCategory($id: ID, $handle: String)

Fetches a single blog category by `id` or `handle`, including its image and SEO metadata. Use on a category landing page (the paginated post list for the category comes from `BlogPosts` with `categoryHandle`). Public; no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
GraphQL operation
query BlogCategory($id: ID, $handle: String) {
blogCategory(id: $id, handle: $handle) {
...BlogCategory
image {
...ImageCard
}
seo {
title
description
}
}
}
Uses fragments: BlogCategory, ImageCard

Tagi blogowe

Lista tagów (chmura tagów, z licznikiem postCount):

BlogTagsqueryBlog
query BlogTags

Lists blog tags with usage counts (`postCount` per tag). Use to render a tag cloud. Public; no auth required.

GraphQL operation
query BlogTags {
blogTags {
...BlogTag
}
}
Uses fragments: BlogTag

Pojedynczy tag po id lub handle — na stronę tagu. Pole seo niesie meta ustawione przez merchanta, a gdy ich nie ustawił — tytuł złożony z nazwy tagu (opisu tag nie ma). Listę wpisów z tagiem pobierasz osobno przez BlogPosts z argumentem tagHandle.

BlogTagqueryBlog
query BlogTag($id: ID, $handle: String)

Fetches a single blog tag by `id` or `handle`, including its SEO metadata (null when the merchant has not set any). Use on a tag landing page (the paginated post list for the tag comes from `BlogPosts` with `tagHandle`). Public; no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
GraphQL operation
query BlogTag($id: ID, $handle: String) {
blogTag(id: $id, handle: $handle) {
...BlogTag
seo {
title
description
}
}
}
Uses fragments: BlogTag

Przypięte produkty (merchandising)

Wpis, kategoria i tag mają pole products — connection produktów przypiętych przez merchanta (bezpośrednio, przez kategorie produktów lub przez kolekcje). Connection jest zwracany zawsze (pusty, gdy nic nie przypięto) i zawiera wyłącznie produkty widoczne w sklepie — ukryte i nieaktywne są automatycznie odsiewane. Paginacja first/after i sortowanie sortKey/reverse działają jak w katalogu.

Produkty przypięte do wpisu:

BlogPostProductsqueryBlog
query BlogPostProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false)

Products the merchant pinned to a blog post — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip inside or below the post. Public; no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$firstInt12No
$afterStringNo
$sortKeyProductSortKeysCREATED_ATNo
$reverseBooleanfalseNo
GraphQL operation
query BlogPostProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false) {
blogPost(id: $id, handle: $handle) {
id
products(first: $first, after: $after, sortKey: $sortKey, reverse: $reverse) {
edges {
node {
...ProductCard
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: PageInfo, ProductCard

Produkty przypięte do kategorii bloga:

BlogCategoryProductsqueryBlog
query BlogCategoryProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false)

Products the merchant pinned to a blog category — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip on the category landing page. Public; no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$firstInt12No
$afterStringNo
$sortKeyProductSortKeysCREATED_ATNo
$reverseBooleanfalseNo
GraphQL operation
query BlogCategoryProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false) {
blogCategory(id: $id, handle: $handle) {
id
products(first: $first, after: $after, sortKey: $sortKey, reverse: $reverse) {
edges {
node {
...ProductCard
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: PageInfo, ProductCard

Produkty przypięte do tagu bloga:

BlogTagProductsqueryBlog
query BlogTagProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false)

Products the merchant pinned to a blog tag — directly, via product categories, or via collections. Always a connection: empty when nothing is pinned; only products visible on the storefront are included. Use to render a product strip on the tag landing page. Public; no auth required.

Variables

NameTypeDefaultRequired
$idIDNo
$handleStringNo
$firstInt12No
$afterStringNo
$sortKeyProductSortKeysCREATED_ATNo
$reverseBooleanfalseNo
GraphQL operation
query BlogTagProducts($id: ID, $handle: String, $first: Int = 12, $after: String, $sortKey: ProductSortKeys = CREATED_AT, $reverse: Boolean = false) {
blogTag(id: $id, handle: $handle) {
id
products(first: $first, after: $after, sortKey: $sortKey, reverse: $reverse) {
edges {
node {
...ProductCard
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
}
Uses fragments: PageInfo, ProductCard

Rekomendacje

Algorithm-driven recommendation engine. Intencja: SIMILAR (alternatywy do tego samego produktu), COMPLEMENTARY (cross-sell), BUNDLE (kup razem).

ProductRecommendationsqueryRecommendations
query ProductRecommendations($productId: ID!, $limit: Int = 8, $intent: RecommendationIntent = SIMILAR)

Returns up to `$limit` recommended products related to `$productId`. Default `$intent: SIMILAR` — products sharing categories or tags. Use on PDP "You may also like" sections. Public; no auth required.

Variables

NameTypeDefaultRequired
$productIdID!Yes
$limitInt8No
$intentRecommendationIntentSIMILARNo
GraphQL operation
query ProductRecommendations($productId: ID!, $limit: Int = 8, $intent: RecommendationIntent = SIMILAR) {
productRecommendations(productId: $productId, limit: $limit, intent: $intent) {
...ProductCard
}
}
Uses fragments: ProductCard

Strony i nawigacja (CMS)

Statyczne strony (Polityka prywatności, Regulamin, About) + nawigacja (drzewo menu z urlami).

Pojedyncza strona

Po id lub handle. Używaj na rutach typu /pages/regulamin.

PagequeryContent: Pages
query Page($handle: String, $id: ID)

Fetches a single CMS page (About, Privacy, Returns Policy, Terms, etc.) by `handle` or `id`. Visibility-gated: returns null if the page is hidden or if its publish date is in the future. Public; no auth required.

Variables

NameTypeDefaultRequired
$handleStringNo
$idIDNo
GraphQL operation
query Page($handle: String, $id: ID) {
page(handle: $handle, id: $id) {
...ShopPage
}
}
Uses fragments: ShopPage

Lista stron (paginowana)

PagesqueryContent: Pages
query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $reverse: Boolean = false, $query: String)

Paginated list of visible, already-published CMS pages. Use for sitemap, footer link list, or page directory. The `query` argument supports text search over the page title/handle. Public; no auth required.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$sortKeyPageSortKeysTITLENo
$reverseBooleanfalseNo
$queryStringNo
GraphQL operation
query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $reverse: Boolean = false, $query: String) {
pages(
first: $first
after: $after
sortKey: $sortKey
reverse: $reverse
query: $query
) {
edges {
node {
...ShopPage
}
cursor
}
pageInfo {
...PageInfo
}
totalCount
}
}
Uses fragments: PageInfo, ShopPage

Drzewo menu po handle (main-menu, footer itd.). Pole url jest budowane server-side z slug/handle zasobu (bez extra round-trip), pole resource rozwiązywane przez DataLoader (max 4 zapytania per call: Category / Collection / Page / Product).

MenuqueryContent: Navigation Menus
query Menu($handle: String!)

Fetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree (up to 3 levels). Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, `PAGE`, or `BRAND` — switch on the type to render the right link target. Each resource-linked item exposes both a pre-resolved `url` (standard `/categories|/collections|/pages|/products|/brands/<handle>` convention) and a typed `resource` union with the raw handle so storefronts with custom routing can construct their own paths instead. All resource lookups are batched per request — no N+1 even for deep menus.

Variables

NameTypeDefaultRequired
$handleString!Yes
GraphQL operation
query Menu($handle: String!) {
menu(handle: $handle) {
...Menu
}
}
Uses fragments: Menu

Konwencja url per typ elementu (industry-standard ścieżki sklepowe):

TypURL
FRONTPAGE/
SEARCH/search
CATALOG/products
BLOG/blog
HTTPRęcznie wpisany URL
CATEGORY/categories/{handle}
COLLECTION/collections/{handle}
PAGE/pages/{handle}
PRODUCT/products/{handle}

Storefront może przepisywać te ścieżki na własne trasy przez Next.js rewrites lub middleware. Pole url zwraca null tylko gdy linkowany zasób został usunięty.

URL Redirects (301 / 302)

Lista przekierowań skonfigurowanych przez merchanta (po migracji ze starego sklepu, kampanie marketingowe itp.). Storefront eksponuje je w middleware.ts lub next.config.js → redirects().

UrlRedirectsqueryContent: URL Redirects
query UrlRedirects($first: Int = 250, $after: String)

Returns the shop's URL redirects (legacy `path` → new `target` mappings). Use server-side at the edge or in SSR to issue 301 redirects for migrated routes (preserves SEO equity). Default page size 250 — most shops fit in a single page.

Variables

NameTypeDefaultRequired
$firstInt250No
$afterStringNo
GraphQL operation
query UrlRedirects($first: Int = 250, $after: String) {
urlRedirects(first: $first, after: $after) {
nodes {
...UrlRedirect
}
pageInfo {
...PageInfo
}
}
}
Uses fragments: PageInfo, UrlRedirect

Lokalizacja per sklep (BOPIS / multi-location)

Dla sklepów z wieloma fizycznymi lokalizacjami (magazyny, sklepy stacjonarne, dropshipperzy). Umożliwia BOPIS (Buy Online, Pick up In Store) — klient wybiera lokalizację odbioru, widzi dostępność per sklep, „Click & Collect" jako alternatywa dla wysyłki.

Dostępność per lokalizacja (na wariancie produktu)

ProductStoreAvailability to query do pobrania produktu wraz z storeAvailability per wariant — Relay Connection z edges / pageInfo / totalCount. Dla sklepów z jedną lokalizacją field zwraca null (kompatybilność wsteczna — storefront może pominąć UI picker).

ProductStoreAvailabilityqueryStore Availability: per-location stock (BOPIS / multi-location)
query ProductStoreAvailability($handle: String, $id: ID)

Fetches a product (by `handle` or `id`) along with per-variant availability across the merchant's physical locations — for the BOPIS / multi-location flow. The `storeAvailability` connection lives on each `ProductVariant`; its arguments (`first`, `after`, `near`, `locationType`) are set inside the `VariantStoreAvailability` fragment. The connection returns null for single-location shops (in which case the storefront can skip the store picker entirely). `availableStock` is null for anonymous users and an integer for authenticated customers. Apply `@inContext(preferredLocationId: ...)` on the operation to pin the customer's preferred location to the top of the result.

Variables

NameTypeDefaultRequired
$handleStringNo
$idIDNo
GraphQL operation
query ProductStoreAvailability($handle: String, $id: ID) {
product(handle: $handle, id: $id) {
id
handle
title
variants {
nodes {
...VariantStoreAvailability
}
}
}
}
Uses fragments: VariantStoreAvailability

Zachowanie pól:

  • availableStock jest token-gatednull dla anonimowych zapytań, Int dla zalogowanego klienta (industry-standard parity)
  • pickupTime to zlokalizowany string PL/EN obliczany z pickupLeadTimeHours (null jeśli pickup wyłączony)
  • Nigdy nie eksponuje pól wewnętrznych: committed, reserved, damaged, safetyStock

Priorytet sortowania storeAvailability:

  1. @inContext(preferredLocationId: $id) — preferowana lokalizacja na górze
  2. near: { latitude, longitude } — rosnąca odległość Haversine
  3. Bez parametrów — priority ASC, potem name ASC

Dyrektywa @inContext(preferredLocationId)

Dyrektywa operacji — pinuje wybraną lokalizację na pierwsze miejsce w storeAvailability. Niepoprawne / nieaktywne ID są cicho ignorowane.

query ProductAvailability($handle: String, $loc: ID!) @inContext(preferredLocationId: $loc) {
product(handle: $handle) {
variants {
nodes {
storeAvailability(first: 10) {
edges { node { isAvailable location { id name } } }
}
}
}
}
}

Ta sama dyrektywa przyjmuje też country, language i currency (typ String — wartość w cudzysłowie, np. @inContext(country: "DE")). Ustalają kontekst żądania z najwyższym priorytetem; wartość nieobsługiwana lub niebędąca kodem jest pomijana i rozstrzyga następne źródło — patrz Przegląd API.

Paginowana lista lokalizacji (store picker UI)

Pod store picker w nagłówku („Wybierz sklep") lub samodzielną mapę lokalizacji.

LocationsqueryLocations (store picker UI)
query Locations($first: Int = 20, $after: String, $near: GeoCoordinateInput, $hasPickupEnabled: Boolean, $locationType: LocationType)

Paginated list of active store locations (default 20, max 100). Filters: `near` (`{ latitude, longitude }`) for proximity search — sorts ascending by distance; `hasPickupEnabled` for pickup-only filtering; `locationType` (`RETAIL`, `WAREHOUSE`, `PICKUP_POINT`). When `near` is omitted, results are sorted by the merchant's `priority`, then name. Use for the BOPIS store picker UI. Public; no auth required.

Variables

NameTypeDefaultRequired
$firstInt20No
$afterStringNo
$nearGeoCoordinateInputNo
$hasPickupEnabledBooleanNo
$locationTypeLocationTypeNo
GraphQL operation
query Locations($first: Int = 20, $after: String, $near: GeoCoordinateInput, $hasPickupEnabled: Boolean, $locationType: LocationType) {
locations(
first: $first
after: $after
near: $near
hasPickupEnabled: $hasPickupEnabled
locationType: $locationType
) {
totalCount
pageInfo {
...PageInfo
}
edges {
cursor
node {
...Location
}
}
}
}
Uses fragments: Location, PageInfo

Pojedyncza aktywna lokalizacja

Po ID. Zwraca null dla nieistniejącej lub nieaktywnej lokalizacji.

LocationqueryLocations (store picker UI)
query Location($id: ID!)

Fetches a single store location by `id` — full address, coordinates, business hours, pickup config (lead time, hours, timezone), and services. Returns null if the location is not found, not active, or owned by another shop. Use on the location detail page. Public; no auth required.

Variables

NameTypeDefaultRequired
$idID!Yes
GraphQL operation
query Location($id: ID!) {
location(id: $id) {
...Location
}
}
Uses fragments: Location

Enum LocationType: WAREHOUSE (magazyn, default), STORE (sklep stacjonarny, BOPIS), DROPSHIPPER, FULFILLMENT_CENTER.

DataLoader batching

storeAvailability używa DataLoader. Przy 30 wariantach na stronie dane są ładowane w 2 zapytaniach (1× liczba aktywnych lokalizacji per shop + 1× batch po variant_id = ANY(...)). Sortowanie i filtrowanie dzieje się w resolverze — nie poison'uje klucza cache.


Ad-hoc queries (schema only)

Następujące queries istnieją w schema, ale nie są pre-built operations w @doswiftly/storefront-operations — odpalaj je jako ad-hoc query (np. przez client.request<T>(gql\...`)`).

Waluty

Multi-currency display. Storefront może pokazywać ceny w wybranej walucie + przeliczać.

query Currencies {
currencies { code name symbol decimalPlaces symbolPosition }
}

query ExchangeRate($from: String!, $to: String!) {
exchangeRate(from: $from, to: $to) # zwraca Float
}

query ConvertCurrency($amount: Float!, $from: String!, $to: String!) {
convertCurrency(amount: $amount, from: $from, to: $to) {
originalAmount originalCurrency
convertedAmount convertedCurrency
rate rateWithMargin marginApplied rateSource rateTimestamp
}
}

query ShopCurrencyConfig {
shopCurrencyConfig { primaryCurrency supportedCurrencies autoConvertPrices }
}

query AllSupportedCurrencies {
allSupportedCurrencies { code name symbol decimalPlaces symbolPosition }
}

query CurrencyInfo($code: String!) {
currencyInfo(code: $code) { code name symbol decimalPlaces symbolPosition }
}

convertCurrency uwzględnia marżę sklepu (admin może ustawić %). allSupportedCurrencies zwraca wszystkie waluty wspierane systemowo (kursy ECB), niezależnie od konfiguracji sklepu.

Język i tłumaczenia

query Languages {
languages { code nativeName englishName direction isDefault }
}

query Translations($input: TranslationsInput!) {
translations(input: $input) {
# zlokalizowane stringi per requested keys
}
}

Unified localization

localization to ujednolicony kontekst lokalizacyjny — dostępne kraje, języki, aktualny kraj i język klienta. Pod picker krajów/języków w storefront.

query Localization {
localization {
availableCountries { id isoCode name currency { isoCode } unitSystem availableLanguages { code nativeName direction isDefault } }
availableLanguages { code nativeName englishName direction isDefault }
country { id isoCode name currency { isoCode } unitSystem }
language { code nativeName englishName direction isDefault }
}
}
  • availableCountries — kraje ze stref wysyłki sklepu (ta sama lista co shop.shipsToCountries), bez krajów objętych sankcjami.
  • country — bieżący kraj z kontekstu żądania (@inContext(country:) → geolokalizacja → kraj domyślny sklepu). Nie jest zawężany do availableCountries: odwiedzający może być w kraju, do którego sklep nie wysyła. Gdy kraju nie da się ustalić, isoCode ma wartość ZZ, a currency to waluta sklepu.
  • name kraju jest po angielsku; w interfejsie w innym języku zbuduj nazwę z isoCode, np. new Intl.DisplayNames([locale], { type: 'region' }).of(isoCode) (dla ZZ pokaż własny tekst, np. „Wybierz kraj").
  • currency i unitSystem kraju to domyślna waluta i system miar tego kraju — informacja prezentacyjna, nie waluta, w której sklep sprzedaje.

Ceny B2B

Grupy klientów i pricing per wariant produktu — dla zalogowanych B2B klientów zwraca najlepszą dostępną cenę (grupa + rabaty wolumenowe), dla gości cenę detaliczną z zachętą do logowania.

query CustomerGroups {
customerGroups { id name code description discountPercent taxExempt }
}

query B2BPricing($variantId: ID!, $retailPrice: Float!, $quantity: Float) {
b2bPricing(variantId: $variantId, retailPrice: $retailPrice, quantity: $quantity) {
pricing {
retailPrice { amount currencyCode }
yourPrice { amount currencyCode }
savings { amount currencyCode }
savingsPercent
hasGroupDiscount
appliedGroup { id name discountPercent }
tierName
}
volumeTiers { minQuantity maxQuantity unitPrice { amount currencyCode } discountPercent }
isAuthenticated
guestMessage
}
}

b2bPricing nie wymaga autoryzacji, ale zalogowani klienci otrzymują ceny grupowe. Dla gości backend zwraca cenę detaliczną z guestMessage (i18n string „Zaloguj się aby zobaczyć cenę B2B").


Treści cyfrowe i załączniki produktu

Sklep może dołączyć do produktu pliki dostępne dla każdego (instrukcje, certyfikaty, karty gwarancyjne) oraz sprzedawać treści wydawane dopiero po opłaceniu zamówienia. To dwa różne mechanizmy i różnią się jedną istotną rzeczą: plik publiczny ma stały adres, kupiony nie ma.

Załączniki na karcie produktu

Adres załącznika jest stały, więc renderuj go jak zwykły odnośnik i spokojnie trzymaj w pamięci podręcznej. Pole rozwiązywane jest leniwie — lista produktów, która o nie nie pyta, nie płaci za dodatkowe zapytanie po stronie serwera, więc pobieraj je dopiero na karcie produktu.

ProductAttachmentsqueryTreści cyfrowe
query ProductAttachments($handle: String!)

Publiczne pliki dołączone do produktu — instrukcje, certyfikaty, karty gwarancyjne. Osobne zapytanie, a nie pole w podstawowym fragmencie produktu: załączniki wymagają dodatkowego odczytu po stronie serwera, więc lista produktów nie powinna za nie płacić. Pobierz je dopiero na karcie produktu.

Variables

NameTypeDefaultRequired
$handleString!Yes
GraphQL operation
query ProductAttachments($handle: String!) {
product(handle: $handle) {
id
attachments {
...ProductAttachment
}
}
}
Uses fragments: ProductAttachment

Materiały wydawane po zakupie nigdy nie pojawią się w tym polu. Nie próbuj ich stamtąd czytać — wymagają uprawnienia wynikającego z opłaconego zamówienia.

Co klient kupił

digitalDownloads na pozycji zamówienia mówi, do czego kupujący ma prawo: nazwa pliku, rozmiar, ile pobrań mu zostało (brak wartości oznacza brak ograniczenia, nie zero) i kiedy dostęp wygasa (brak oznacza bezterminowo).

Wpis z ready: false znaczy, że plik jest jeszcze sprawdzany po stronie platformy — pokaż stan oczekiwania, a nie błąd. Klient, który przed chwilą zapłacił, ma zobaczyć „przygotowujemy plik", a nie pustą listę sugerującą, że niczego nie kupił.

OrderDigitalDownloadsqueryTreści cyfrowe
query OrderDigitalDownloads($token: String!, $email: String)

Treści cyfrowe kupione w zamówieniu, po opaque tokenie zamówienia (strona po-zakupowa gościa). Osobne zapytanie z tego samego powodu co wyżej — lista zamówień nie musi rozwiązywać pobrań dla każdej pozycji.

Variables

NameTypeDefaultRequired
$tokenString!Yes
$emailStringNo
GraphQL operation
query OrderDigitalDownloads($token: String!, $email: String) {
orderByToken(token: $token, email: $email) {
id
lineItems(first: 100) {
edges {
node {
id
title
digitalDownloads {
...DigitalDownload
}
}
}
}
}
}
Uses fragments: DigitalDownload

Samego pliku nie da się stąd pobrać — odnośnik wydaje osobna mutacja, opisana w Mutacjach.


Powiązane sekcje

  • Mutacje — zapis stanu (cart, checkout, customer auth, returns, reviews, wishlist)
  • Types Reference — pełna referencja typów (objects / inputs / enums / scalars)
  • Konwencje nazewniczenode / edge / cursor w Relay Connection, naming xxxByXxx dla pojedynczych encji
  • SDK — Storefront SDK — typed hooks i providery konsumujące te operacje