E-shop
Products, services, providers, orders, checkout, and payment processing
The E-shop module provides complete commerce functionality including product management, service scheduling, carts, order processing, and checkout.
For storefronts, prefer the high-level store from arky-sdk/storefront-store. It wraps the lower-level methods on this page and keeps CMS state, e-shop state, profile session, cart, quote, checkout, and scheduled service state in one reactive API.
import { createArkyStore } from 'arky-sdk/storefront-store';
const arkyStore = createArkyStore({ baseUrl, storeId, market: 'us', locale: 'en' });
await arkyStore.setup({ hydrateCart: true });
await arkyStore.eshop.cart.addProduct(product, variant, 1);
const quote = await arkyStore.eshop.cart.quote();
const order = await arkyStore.eshop.cart.checkout({ payment_method_id: 'cash' });
Products
Create Product
/v1/stores/{storeId}/products sdk.eshop.product.create() Create a new product. New products start in the active state.
const result = await sdk.eshop.product.create({
key: 'premium-widget',
slug: { en: 'premium-widget' },
taxonomies: [
{ taxonomy_id: 'tax_category', entry_ids: ['ent_widgets'] }
],
blocks: [
{
key: 'details',
type: 'TEXT',
content: {
body: { en: 'Product specifications...' }
}
}
],
variants: [
{
sku: 'WIDGET-SM',
prices: [{ market: 'USD', amount: 2999 }],
inventory: [{ location_id: 'loc_warehouse', available: 100 }],
attributes: [],
weight: 500
},
{
sku: 'WIDGET-LG',
prices: [{ market: 'USD', amount: 3999 }],
inventory: [{ location_id: 'loc_warehouse', available: 50 }],
attributes: [],
weight: 750
}
]
});Parameters
| Name | Type | Description |
|---|---|---|
key required | string | Unique product key identifier |
slug optional | Record<string, string> | Locale-keyed URL slugs (e.g., {en: 'my-product'}) |
blocks optional | Block[] | Content blocks for product details |
taxonomies optional | TaxonomyEntry[] | Taxonomy entries the product belongs to (category, collection, etc.) |
variants optional | Variant[] | Product variants (sku, prices, inventory, attributes, weight) |
Get Product
/v1/stores/{storeId}/products/{id} sdk.eshop.product.get() Retrieve a product by ID or slug.
// By ID
const result = await sdk.eshop.product.get({
id: 'prod_xyz789'
});
// By slug (locale-aware)
const result = await sdk.eshop.product.get({
slug: 'premium-widget'
});
Parameters
| Name | Type | Description |
|---|---|---|
id optional | string | Product ID (use this OR slug) |
slug optional | string | Product slug (locale-aware lookup) |
List Products
/v1/stores/{storeId}/products sdk.eshop.product.find() List products with filtering and pagination.
const result = await sdk.eshop.product.find({
ids: ['prod_1', 'prod_2'],
taxonomyQuery: [
{ taxonomy_id: 'tax_category', entry_ids: ['ent_widgets'] }
],
match_all: true,
status: 'active',
query: 'premium',
sort_field: 'created_at',
sort_direction: 'desc',
cursor: null,
limit: 20,
created_at_from: 1704067200,
created_at_to: 1706745600
});
const { items, cursor } = result;
items.forEach(product => {
console.log(product.key, product.variants);
});Parameters
| Name | Type | Description |
|---|---|---|
ids optional | string[] | Filter by specific product IDs |
taxonomy_query optional | TaxonomyQuery[] | Filter by taxonomy entries (category, collection, etc.) |
match_all optional | boolean | If true, match all taxonomy filters (AND); if false, match any (OR) |
status optional | active | archived | Filter by product status |
query optional | string | Search query in product content |
sort_field optional | string | Sort field (createdAt, updatedAt, etc.) |
sort_direction optional | asc | desc | Sort direction |
cursor optional | string | Pagination cursor |
limit optional | number | Items per page (max 100) |
created_at_from optional | number | Filter by creation date (Unix timestamp) |
created_at_to optional | number | Filter by creation date (Unix timestamp) |
Update Product
/v1/stores/{storeId}/products/{id} sdk.eshop.product.update() Update an existing product. Use status to archive or re-activate a product.
const result = await sdk.eshop.product.update({
id: 'prod_xyz789',
key: 'updated-widget',
slug: { en: 'updated-widget', es: 'widget-actualizado' },
taxonomies: [
{ taxonomy_id: 'tax_category', entry_ids: ['ent_widgets', 'ent_sale'] }
],
blocks: [/* updated blocks */],
variants: [
{
id: 'var_existing',
sku: 'WIDGET-SM-V2',
prices: [{ market: 'USD', amount: 3499 }],
inventory: [{ location_id: 'loc_warehouse', available: 150 }],
attributes: [],
weight: 500
}
],
status: 'active'
});
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Product ID to update |
key optional | string | Product key identifier |
slug optional | Record<string, string> | Locale-keyed URL slugs |
blocks optional | Block[] | Content blocks |
taxonomies optional | TaxonomyEntry[] | Taxonomy entries the product belongs to |
variants optional | Variant[] | Product variants (id, sku, prices, inventory, attributes, weight) |
status optional | active | archived | Product status |
Delete Product
/v1/stores/{storeId}/products/{id} sdk.eshop.product.delete() Delete a product.
await sdk.eshop.product.delete({
id: 'prod_xyz789'
});
Services
Services are schedulable catalog items. Providers supply capacity and working rules for those services.
Create Service
/v1/stores/{storeId}/services sdk.eshop.service.create() const service = await sdk.eshop.service.create({
key: 'deep-cleaning',
slug: { en: 'deep-cleaning' },
blocks: [/* service content */],
prices: [{ market: 'USD', amount: 12000 }]
});
List Services
/v1/stores/{storeId}/services sdk.eshop.service.find() const { items: services } = await sdk.eshop.service.find({
query: 'cleaning',
statuses: ['active'],
limit: 20
});
Connect Providers
/v1/stores/{storeId}/service-providers sdk.eshop.service.createProvider() await sdk.eshop.service.createProvider({
service_id: service.id,
provider_id: provider.id,
working_days: [
{
day: 'monday',
windows: [{ from: '09:00', to: '17:00' }]
}
],
specific_dates: [],
durations: [{ duration: 60 }],
prices: [{ market: 'USD', amount: 12000 }],
slot_interval: 30
});
Providers
Create Provider
/v1/stores/{storeId}/providers sdk.eshop.provider.create() const provider = await sdk.eshop.provider.create({
key: 'north-team',
slug: { en: 'north-team' },
blocks: [/* provider profile */]
});
List Providers
/v1/stores/{storeId}/providers sdk.eshop.provider.find() const { items: providers } = await sdk.eshop.provider.find({
service_id: service.id,
limit: 20
});
Orders
Carts
/v1/storefront/{storeId}/carts/current sdk.eshop.cart.current() Get or create the authenticated profile’s active cart. Orders are created by checking out a cart; every order stores source_cart_id.
const cart = await sdk.eshop.cart.current();
await sdk.eshop.cart.update({
id: cart.id,
market: 'us',
items: [
{ type: 'product', product_id: 'prod_xyz789', variant_id: 'var_small', quantity: 2 },
{
type: 'service',
service_id: 'svc_cleaning',
provider_id: 'prv_north',
slots: [{ from: 1780300800, to: 1780304400 }]
}
],
shipping_address: {
name: 'Jane Doe',
street1: '456 Profile Ave',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
},
forms: [
{
key: 'shipping-notes',
entries: [{ key: 'note', value: 'Leave at door' }]
}
]
});
const quote = await sdk.eshop.cart.quote({ id: cart.id });
const result = await sdk.eshop.cart.checkout({ id: cart.id, payment_method_id: 'credit_card' });
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Cart ID |
market optional | string | Market key, for example us or eu |
items optional | CheckoutItem[] | Cart items. Product lines use type: 'product', product_id, variant_id, quantity; service appointment lines use type: 'service', service_id, provider_id, slots. |
shipping_address optional | Address | Shipping address |
billing_address optional | Address | Billing address |
forms optional | FormEntry[] | Cart form entries (profile info, notes, etc.) |
payment_method_id optional | string | Market payment method ID such as 'cash' or 'credit_card', supplied at checkout or saved on the cart |
Get Order
/v1/stores/{storeId}/orders/{id} sdk.eshop.order.get() Retrieve an order by ID.
const order = await sdk.eshop.order.get({
id: 'ord_xyz789'
});
console.log(order.status, order.workflow_status, order.total, order.items);
Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Order ID |
List Orders
/v1/stores/{storeId}/orders sdk.eshop.order.find() List orders with filtering. Orders have two status fields: status (active / archived) for soft archival, and workflow_status for the payment/fulfillment lifecycle.
const result = await sdk.eshop.order.find({
profile_id: 'acc_profile123',
status: 'active',
workflow_status: 'confirmed',
product_ids: ['prod_xyz789'],
query: '[email protected]',
sort_field: 'created_at',
sort_direction: 'desc',
cursor: null,
limit: 50,
created_at_from: 1704067200,
created_at_to: 1735689600
});
result.items.forEach(order => {
console.log(order.id, order.status, order.workflow_status, order.total);
});Parameters
| Name | Type | Description |
|---|---|---|
profile_id optional | string | Filter by profile account ID |
status optional | active | archived | Filter by order archival status |
workflow_status optional | string | Filter by workflow status: created, pending, authorized, confirmed, completed, cancelled, failed |
product_ids optional | string[] | Filter by products in order |
audience_id optional | string | Filter by audience |
query optional | string | Search query |
sort_field optional | string | Sort field |
sort_direction optional | asc | desc | Sort direction |
cursor optional | string | Pagination cursor |
limit optional | number | Items per page |
created_at_from optional | number | Filter by creation date (Unix timestamp) |
created_at_to optional | number | Filter by creation date (Unix timestamp) |
Update Order
/v1/stores/{storeId}/orders/{id} sdk.eshop.order.update() Update an order’s archival state, workflow status, addresses, form entries, items, or payment.
// Advance the workflow
await sdk.eshop.order.update({
id: 'ord_xyz789',
workflow_status: 'confirmed'
});
// Archive an order
await sdk.eshop.order.update({
id: 'ord_xyz789',
status: 'archived'
});
// Update addresses / form entries
await sdk.eshop.order.update({
id: 'ord_xyz789',
shipping_address: {
name: 'Jane Doe',
street1: '456 Profile Ave',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
},
forms: [
{ key: 'notes', entries: [{ key: 'note', value: 'Leave at door' }] }
],
items: [
{ product_id: 'prod_xyz', variant_id: 'var_1', quantity: 2 }
]
});Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Order ID to update |
status optional | active | archived | Archival status |
workflow_status optional | string | Workflow status: created, pending, authorized, confirmed, completed, cancelled, failed |
shipping_address optional | Address | null | Shipping address (pass null to clear) |
billing_address optional | Address | null | Billing address (pass null to clear) |
forms optional | FormEntry[] | Order form entries |
items optional | CheckoutItem[] | Order items. Product and service appointment lines are both supported. |
payment optional | Payment | Payment object update |
status controls whether the order is visible in the active list or archived. workflow_status drives the payment and fulfillment lifecycle and is usually advanced by the server (checkout, webhooks, etc.).
Checkout
Cart Quote
/v1/storefront/{storeId}/carts/{id}/quote sdk.eshop.cart.quote() Calculate a cart total before checkout. Storefront checkout is cart-backed: update the cart first, then quote or checkout it. The SDK injects storeId and market from the client config.
const cart = await sdk.eshop.cart.current();
await sdk.eshop.cart.update({
id: cart.id,
items: [
{ type: 'product', product_id: 'prod_xyz789', variant_id: 'var_small', quantity: 2 },
{
type: 'service',
service_id: 'svc_cleaning',
provider_id: 'prv_north',
slots: [{ from: 1780300800, to: 1780304400 }]
}
],
payment_method_id: 'credit_card',
shipping_method_id: 'ship_standard',
promo_code: 'SAVE10',
shipping_address: {
name: 'Jane Doe',
street1: '456 Profile Ave',
city: 'New York',
country: 'US',
state: 'NY',
postal_code: '10001'
}
});
const quote = await sdk.eshop.cart.quote({ id: cart.id });
console.log('Subtotal:', quote.subtotal);
console.log('Discount:', quote.discount);
console.log('Shipping:', quote.shipping);
console.log('Tax:', quote.tax);
console.log('Total:', quote.total);Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Cart ID to quote |
store_id required | string | Store ID |
Cart Checkout
/v1/storefront/{storeId}/carts/{id}/checkout sdk.eshop.cart.checkout() Process payment and complete a cart. The SDK injects storeId from the client config. The checkout response includes order_id, order number, a Stripe client_secret (when 3DS or additional confirmation is required), and the payment object.
const cart = await sdk.eshop.cart.current();
await sdk.eshop.cart.update({
id: cart.id,
items: [
{ type: 'product', product_id: 'prod_xyz789', variant_id: 'var_small', quantity: 2 }
],
shipping_method_id: 'ship_standard',
shipping_address: {
name: 'Jane Doe',
street1: '456 Profile Ave',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
},
forms: [
{
key: 'profile-info',
entries: [
{ key: 'email', value: '[email protected]' },
{ key: 'firstName', value: 'John' },
{ key: 'lastName', value: 'Doe' }
]
}
],
promo_code: 'SAVE10'
});
const result = await sdk.eshop.cart.checkout({
id: cart.id,
payment_method_id: 'credit_card'
});
if (result.client_secret) {
// Additional confirmation (e.g. 3D Secure) required on the client
const { error } = await stripe.confirmCardPayment(result.client_secret);
if (error) throw new Error(error.message);
}
console.log('Order placed:', result.order_id, result.number);Parameters
| Name | Type | Description |
|---|---|---|
id required | string | Cart ID |
shipping_method_id optional | string | Selected shipping method. Required for shipped product carts, not service-only carts. |
payment_method_id optional | string | Market payment method ID such as 'cash' or 'credit_card' |
shipping_address optional | Address | Shipping address |
billing_address optional | Address | Billing address |
forms optional | FormEntry[] | Order form entries (profile info, notes, etc.) |
promo_code optional | string | Applied promo code |
Complete Checkout Flow
import { loadStripe } from '@stripe/stripe-js';
import { createArkyStore } from 'arky-sdk/storefront-store';
const stripe = await loadStripe('pk_live_xxx');
const arkyStore = createArkyStore({ baseUrl, storeId, market: 'us', locale: 'en' });
async function checkout() {
await arkyStore.setup({ hydrateCart: true });
// 1. Quote the backend cart to show prices
const quote = await arkyStore.eshop.cart.quote({
shipping_method_id: selectedShipping,
shipping_address: shippingAddress,
forms: [
{
key: 'profile',
entries: [
{ key: 'email', value: profileEmail },
{ key: 'firstName', value: profileFirstName },
{ key: 'lastName', value: profileLastName }
]
}
],
promo_code: promoCodeInput
});
console.log('Total:', quote?.payment.total);
// 2. Checkout with the selected market payment method
const result = await arkyStore.eshop.cart.checkout({
payment_method_id: 'credit_card'
});
if (result.client_secret) {
// Handle 3D Secure / additional confirmation
const { error } = await stripe.confirmCardPayment(result.client_secret, {
payment_method: {
card: cardElement,
billing_details: { email: profileEmail }
}
});
if (error) throw new Error(error.message);
}
return result.order_id;
}
Use arkyStore.eshop.cart.quote to show price breakdowns before the profile commits to purchase.
Availability
/v1/stores/{storeId}/services/availability sdk.eshop.service.getAvailability() Availability belongs to services because the profile is choosing schedulable service capacity. Checkout still reserves the selected slots on the unified order.
const availability = await sdk.eshop.service.getAvailability({
service_id: 'svc_cleaning',
provider_id: 'prv_north',
from: 1780272000,
to: 1782864000
});
Parameters
| Name | Type | Description |
|---|---|---|
service_id required | string | Service to schedule |
provider_id optional | string | Provider to check, or omit to include all eligible providers |
from required | number | Start of the availability window as a Unix timestamp |
to required | number | End of the availability window as a Unix timestamp |