dist/cursor/saleor-commerce/skills/saleor-graphql/SKILL.md
Work with the Saleor GraphQL API — queries, mutations, subscriptions, cursor pagination, filters, error handling, GraphQL Playground, and code generation. Use when building against the Saleor API.
npx skillsauth add orcaqubits/agentic-commerce-claude-plugins saleor-graphqlInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch live docs:
https://docs.saleor.io/docs/developer/api-reference for API reference overviewsite:docs.saleor.io GraphQL queries mutations examples for query patternssite:docs.saleor.io cursor pagination first after for pagination referencesite:docs.saleor.io authentication JWT token for auth token handlingsite:docs.saleor.io GraphQL error handling for mutation error patternshttps://docs.saleor.io/docs/developer/api-conventions for API conventionsSaleor exposes its entire functionality through a single GraphQL endpoint. There is no REST API -- all interactions (storefront, dashboard, apps, integrations) use GraphQL exclusively.
| Aspect | Detail |
|--------|--------|
| Endpoint | /graphql/ |
| Protocol | HTTP POST with JSON body |
| Introspection | Enabled by default (disable in production if needed) |
| Playground | Available at the API URL in browser |
| Schema | Single unified schema for all consumers |
| Method | Use Case | Header |
|--------|----------|--------|
| JWT (Staff) | Dashboard operations, admin mutations | Authorization: Bearer <token> |
| JWT (Customer) | Storefront customer actions | Authorization: Bearer <token> |
| App Token | App-to-Saleor API calls | Authorization: Bearer <app-token> |
| No Auth | Public storefront queries (products, collections) | None required |
| Operation | Mutation |
|-----------|---------|
| Staff login | tokenCreate(email, password) |
| Customer login | tokenCreate(email, password) |
| Refresh token | tokenRefresh(refreshToken) |
| Verify token | tokenVerify(token) |
Tokens are short-lived JWTs. Always use tokenRefresh to obtain new access tokens rather than re-authenticating.
| Query | Purpose |
|-------|---------|
| products(first, after, filter, channel) | List products with pagination |
| product(id, slug, channel) | Single product by ID or slug |
| categories(first, after, filter) | List categories |
| collections(first, after, filter, channel) | List collections |
| Query | Purpose |
|-------|---------|
| orders(first, after, filter) | List orders (staff) |
| order(id) | Single order detail |
| me { orders } | Customer's own orders |
| draftOrders(first, after) | List draft orders (staff) |
Most storefront queries require a channel argument to scope results:
query Products($channel: String!) {
products(first: 10, channel: $channel) {
edges { node { id name pricing { ... } } }
}
}
Queries without a channel argument return data across all channels (staff only).
Saleor uses Relay-style cursor pagination throughout its API:
| Parameter | Type | Purpose |
|-----------|------|---------|
| first | Int | Number of items from the start |
| after | String | Cursor to paginate forward |
| last | Int | Number of items from the end |
| before | String | Cursor to paginate backward |
| Field | Purpose |
|-------|---------|
| edges[].node | The actual data object |
| edges[].cursor | Opaque cursor for this edge |
| pageInfo.hasNextPage | Whether more items exist forward |
| pageInfo.hasPreviousPage | Whether more items exist backward |
| pageInfo.startCursor | Cursor of the first edge |
| pageInfo.endCursor | Cursor of the last edge |
| totalCount | Total number of matching items |
Saleor provides typed filter input objects for each queryable resource:
| Filter Input | Key Fields |
|-------------|-----------|
| ProductFilterInput | search, price, categories, collections, productTypes, isPublished |
| OrderFilterInput | created, status, customer, paymentStatus |
| CustomerFilterInput | search, dateJoined, numberOfOrders |
Filters are passed as the filter argument on list queries.
Saleor mutations return the result alongside an errors array in the response:
| Field | Purpose |
|-------|---------|
| <entity> | The created/updated object on success |
| errors | Array of { field, message, code } on failure |
| Code | Meaning |
|------|---------|
| REQUIRED | A required field is missing |
| INVALID | Field value is invalid |
| NOT_FOUND | Referenced object does not exist |
| UNIQUE | Value violates a uniqueness constraint |
| GRAPHQL_ERROR | General GraphQL execution error |
Always check the errors array -- a mutation may return HTTP 200 with validation errors in the response body.
Saleor supports GraphQL subscriptions for real-time webhook payloads:
| Aspect | Detail |
|--------|--------|
| Transport | Webhook POST (not WebSocket) |
| Definition | Subscription query defines the payload shape |
| Registration | Via App manifest or webhookCreate mutation |
| Use Case | Custom webhook payloads with only the fields you need |
Subscription queries are attached to webhook configurations to define exactly which fields are delivered in the payload.
The built-in Playground is available at the API endpoint URL in a browser:
| Feature | Detail |
|---------|--------|
| Schema explorer | Browse all types, queries, mutations |
| Query editor | Write and execute queries with autocomplete |
| Auth header | Add Authorization: Bearer <token> in HTTP Headers panel |
| History | Previously executed queries are saved |
| Docs panel | Inline documentation for all fields |
| Tool | Purpose |
|------|---------|
| graphql-codegen | Generate TypeScript types from Saleor schema |
| @graphql-codegen/typed-document-node | Typed document nodes for queries |
| @graphql-codegen/introspection | Generate introspection JSON |
# codegen.yml — Fetch live docs for current config shape
schema: "https://your-saleor-instance.com/graphql/"
documents: "src/**/*.graphql"
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
channel argumentfirst/after) -- never request unbounded listserrors array on every mutation response, even on HTTP 200tokenRefresh to renew JWTs instead of storing long-lived tokensFetch the Saleor GraphQL API documentation for exact query signatures, filter input types, and mutation patterns before implementing.
development
Build with Spree's headless Next.js storefront — the official `spree/storefront` repo (Next.js 16 App Router with Server Actions and Turbopack, React 19 Server Components, Tailwind CSS 4, TypeScript 5, `@spree/sdk`, Sentry), server-only auth (httpOnly JWT cookies + publishable key), MeiliSearch faceted catalog, one-page checkout with Apple/Google Pay/Klarna/Affirm/SEPA, multi-region market routing, GA4 + JSON-LD SEO, and Vercel/Docker deployment. Use when forking or customizing the storefront, or evaluating headless adoption.
tools
Build Spree extensions as Rails engines — gem scaffolding, `bin/rails g spree:extension`, mounting routes/migrations/assets, the modern `prepend` decorator pattern (`*_decorator.rb` with `self.prepended(base)`), generators (`spree:model_decorator`, `spree:controller_decorator`), the four customization surfaces in preference order (Events > Webhooks > Dependencies > Decorators), Spree::Dependencies for swapping service objects, gem release/versioning, and the deprecated Deface engine. Use when building a reusable Spree extension or adding non-trivial customization to an app.
development
Build with Spree's event bus and Webhooks 2.0 — `Spree::Events` publication, `Spree::Subscriber` DSL with `subscribes_to` and `on`, wildcard matching, lifecycle events (`{model}.created/.updated/.deleted` via `publishes_lifecycle_events`), the canonical event catalog (order.*, payment.*, shipment.*, product.*), Webhooks 2.0 endpoints, HMAC-SHA256 signing (`X-Spree-Webhook-Signature`), exponential-backoff retries, and Sidekiq job orchestration. Use when wiring event-driven business logic, building webhook consumers, or replacing ActiveSupport callback chains.
tools
Cross-cutting Spree development patterns — the customization preference hierarchy (Events > Webhooks > Dependencies > Decorators), `Spree::Dependencies` service-object swapping, the `_decorator.rb` + `prepend` + `self.prepended` idiom, idempotent subscribers and webhook receivers, multi-store scoping discipline, prefixed IDs, calculator polymorphism (shipping/promotion/tax share the base), service-object composition with `dry-monads` or simple results, why to avoid `class_eval` reopening and Deface, and Spree-on-Rails idioms (Hotwire/Turbo Stimulus, ActiveStorage, Action Cable, Sidekiq). Use when designing the architecture of a Spree extension or solving cross-cutting concerns.