Back to Arky

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. It wraps the lower-level methods on this page and keeps CMS state, e-shop state, contact session, cart, quote, checkout, and scheduled service state in one reactive API.

import { initialize } from "arky-sdk/storefront";

const arky = initialize("arky_pk_...", {
	market: "us",
	locale: "en",
});

await arky.eshop.cart.load();
await arky.eshop.cart.addProduct(product, variant, 1);
const quote = await arky.eshop.cart.quote();
const order = await arky.eshop.cart.checkout({ payment_method_key: "cash" });

Products

Create Product

POST /v1/stores/{storeId}/products
SDK: 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',
    id: 'details',
    type: 'localized_text',
    properties: {},
    value: { en: 'Product specifications...' }
  }
],
variants: [
  {
    sku: 'WIDGET-SM',
    prices: [{ market: 'us', currency: 'usd', amount: 2999 }],
    inventory: [{ location_id: 'loc_warehouse', available: 100 }],
    attributes: [],
    weight: 500
  },
  {
    sku: 'WIDGET-LG',
    prices: [{ market: 'us', currency: '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 ProductVariant[] Product variants, prices, inventory, tax, weight, and shipping policy

Get Product

GET /v1/stores/{storeId}/products/{id}
SDK: sdk.eshop.product.get()

Retrieve the lean catalog product by ID or slug. Variants include prices and catalog configuration, but not location stock. Fetch inventory explicitly when the view needs it.

// 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)

Get Product Inventory

GET /v1/stores/{storeId}/products/{id}/inventory
SDK: sdk.eshop.product.getInventory()

Inventory changes independently from product content and is therefore a separate resource. Load it only for stock-aware detail, cart, or operator views.

const [product, inventory] = await Promise.all([
	sdk.eshop.product.get({ id: "prod_xyz789" }),
	sdk.eshop.product.getInventory({ id: "prod_xyz789" }),
]);

const selectedStock = inventory.filter(
	(row) => row.variant_id === product.variants[0]?.id,
);

List Products

GET /v1/stores/{storeId}/products
SDK: 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 | draft | 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

PUT /v1/stores/{storeId}/products/{id}
SDK: sdk.eshop.product.update()

Update an existing product. Use status to draft, 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: "us", currency: "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 ProductVariant[] Product variants, prices, inventory, tax, weight, and shipping policy
status optional active | draft | archived Product status

Delete Product

DELETE /v1/stores/{storeId}/products/{id}
SDK: 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

POST /v1/stores/{storeId}/services
SDK: sdk.eshop.service.create()
const service = await sdk.eshop.service.create({
	key: "deep-cleaning",
	slug: { en: "deep-cleaning" },
	blocks: [/* service content */],
});

List Services

GET /v1/stores/{storeId}/services
SDK: sdk.eshop.service.find()
const { items: services } = await sdk.eshop.service.find({
	query: "cleaning",
	statuses: ["active"],
	limit: 20,
});

Connect Providers

POST /v1/stores/{storeId}/service-providers
SDK: 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: "us", currency: "usd", amount: 12000 }],
	slot_interval: 30,
});

Providers

Create Provider

POST /v1/stores/{storeId}/providers
SDK: sdk.eshop.provider.create()
const provider = await sdk.eshop.provider.create({
	key: "north-team",
	slug: { en: "north-team" },
	blocks: [/* provider contact */],
});

List Providers

GET /v1/stores/{storeId}/providers
SDK: sdk.eshop.provider.find()
const { items: providers } = await sdk.eshop.provider.find({
	service_id: service.id,
	limit: 20,
});

Orders

Carts

POST /v1/storefront/carts/current
SDK: arky.client.eshop.cart.current()

Get or create the authenticated contact’s active cart. Orders are created by checking out a cart; every order stores source_cart_id.

const cart = await arky.client.eshop.cart.current();

await arky.client.eshop.cart.update({
	id: cart.id,
	market: "us",
	product_items: [
		{
			product_id: "prod_xyz789",
			variant_id: "var_small",
			quantity: 2,
		},
	],
	booking_items: [
		{
			service_id: "svc_cleaning",
			provider_id: "prv_north",
			slots: [{ from: 1780300800, to: 1780304400 }],
		},
	],
	shipping_address: {
		name: "Jane Doe",
		street1: "456 Contact 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 arky.client.eshop.cart.quote({ id: cart.id });
const result = await arky.client.eshop.cart.checkout({
	id: cart.id,
	payment_method_key: "cash",
});

Parameters

Name Type Description
id required string Cart ID
market optional string Market key, for example us or eu
product_items optional CartProduct[] Cart product lines with product_id, variant_id, and quantity
booking_items optional CartBooking[] Scheduled-service selections with service_id, provider_id, and slots
shipping_address optional Address Shipping address
billing_address optional Address Billing address
forms optional FormEntry[] Cart form entries (contact info, notes, etc.)
payment_method_key optional string Market payment method key such as 'cash' or 'credit_card', supplied at checkout or saved on the cart

Get Order

GET /v1/stores/{storeId}/orders/{id}
SDK: sdk.eshop.order.get()

Retrieve an order by ID.

const order = await sdk.eshop.order.get({
	id: "ord_xyz789",
});

const [payment, products, bookings, digitalProducts] = await Promise.all([
	sdk.eshop.order.getPayment({ order_id: order.id }),
	sdk.eshop.order.getProducts({ id: order.id }),
	sdk.eshop.order.getBookings({ id: order.id }),
	sdk.eshop.order.getDigitalProducts({ id: order.id }),
]);

console.log(order.status, payment.status, order.fulfillment_status);

Parameters

Name Type Description
id required string Order ID

List Orders

GET /v1/stores/{storeId}/orders
SDK: sdk.eshop.order.find()

List lean orders with filtering. status is the order lifecycle and fulfillment_status is its bounded summary. Payment, products, bookings, and digital products are separate resources; request only the children a detail screen needs.

const result = await sdk.eshop.order.find({
contact_id: 'acc_contact123',
statuses: ['confirmed'],
product_statuses: ['confirmed'],
booking_statuses: ['confirmed'],
product_ids: ['prod_xyz789'],
service_ids: ['svc_consultation'],
provider_ids: ['provider_123'],
query: 'john@example.com',
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.payment_id, order.fulfillment_status, order.money.total);
});

Parameters

Name Type Description
contact_id optional string Filter by contact ID
statuses optional string[] Filter by order lifecycle status: pending, confirmed, partially_cancelled, cancelled
product_statuses optional string[] Filter by product-line status: pending, confirmed, cancelled
booking_statuses optional string[] Filter by booking status: pending, confirmed, completed, no_show, cancelled
product_ids optional string[] Filter by products in order
service_ids optional string[] Filter by scheduled services in order
provider_ids optional string[] Filter by scheduled-service providers in order
verified optional boolean Filter by order verification state
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

PUT /v1/stores/{storeId}/orders/{id}
SDK: sdk.eshop.order.update()

Update an order’s confirmation/cancellation state, addresses, form entries, products, or bookings.

Direct cancellation is only available while the order has no unreversed payment, refund, fulfillment, or shipment effects. Refund a captured payment through the refund API and reverse any other owning lifecycle before cancelling the order.

// Confirm a pending order
await sdk.eshop.order.update({
id: 'ord_xyz789',
version: 4,
confirm: true
});

// Cancel an order
await sdk.eshop.order.update({
id: 'ord_xyz789',
version: 4,
cancel: true
});

// Update addresses / form entries
await sdk.eshop.order.update({
id: 'ord_xyz789',
version: 4,
shipping_address: {
name: 'Jane Doe',
street1: '456 Contact Ave',
city: 'New York',
state: 'NY',
postal_code: '10001',
country: 'US'
},
forms: [
{ key: 'notes', entries: [{ key: 'note', value: 'Leave at door' }] }
],
product_items: [
{ product_id: 'prod_xyz', variant_id: 'var_1', quantity: 2 }
],
booking_items: [
{
service_id: 'svc_cleaning',
provider_id: 'prv_north',
slots: [{ from: 1780300800, to: 1780304400 }]
}
]
});

Parameters

Name Type Description
id required string Order ID to update
version required number Current Order version returned by the latest read. A stale version returns HTTP 409.
confirm optional boolean Confirm pending products and bookings when payment rules allow it
cancel optional boolean Cancel an order with no unreversed lifecycle effects and release reserved availability. Captured payments must be refunded first.
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
product_items optional TrustedCartProductInput[] Replacement product lines for the order
booking_items optional TrustedCartBookingInput[] Replacement scheduled-service bookings for the order
Note

status and fulfillment_status are returned on the lean order. The order’s payment_id points to its one separate payment; load that payment only when the view needs payment lifecycle. Fulfillment summarizes physical shipments and scheduled-service work.

Order Payment and Operations

Use the order-scoped APIs when you need payment or independent operation detail:

| Resource | Route | SDK | | --- | --- | --- | | Payment | GET /v1/stores/{storeId}/orders/{orderId}/payment | sdk.eshop.order.getPayment() | | Refunds | GET /v1/stores/{storeId}/orders/{orderId}/refunds | sdk.eshop.order.getRefunds() | | Refund | GET /v1/stores/{storeId}/orders/{orderId}/refunds/{refundId} | sdk.eshop.order.getRefund() | | Disputes | GET /v1/stores/{storeId}/orders/{orderId}/disputes | sdk.eshop.order.getDisputes() | | Dispute | GET /v1/stores/{storeId}/orders/{orderId}/disputes/{disputeId} | sdk.eshop.order.getDispute() |

Create a partial or full refund with a caller-owned stable ID. Reuse the same ID and exact payload after an interrupted request; never generate a fresh ID in an automatic retry.

const refund = await sdk.eshop.order.createRefund({
	order_id: "ord_xyz789",
	refund_id: crypto.randomUUID(),
	amount: 2500,
});

Payment, refunds, and disputes are not generic transaction-log rows. The one OrderPayment owns checkout and settlement; zero-to-many refunds and disputes own their independent amounts, provider evidence, statuses, errors, and timestamps.

Checkout

Cart Quote

POST /v1/storefront/carts/{id}/quote
SDK: arky.client.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 sends the Store’s publishable key and the current market context; callers never supply a Store ID.

const cart = await arky.client.eshop.cart.current();
await arky.client.eshop.cart.update({
id: cart.id,
product_items: [
  { product_id: 'prod_xyz789', variant_id: 'var_small', quantity: 2 }
],
booking_items: [
  {
    service_id: 'svc_cleaning',
    provider_id: 'prv_north',
    slots: [{ from: 1780300800, to: 1780304400 }]
  }
],
payment_method_key: 'credit_card',
shipping_method_id: 'ship_standard',
promo_code: 'SAVE10',
shipping_address: {
  name: 'Jane Doe',
  street1: '456 Contact Ave',
  city: 'New York',
  country: 'US',
  state: 'NY',
  postal_code: '10001'
}
});

const quote = await arky.client.eshop.cart.quote({ id: cart.id });

console.log('Subtotal:', quote.money.subtotal);
console.log('Discount:', quote.money.discount);
console.log('Shipping:', quote.money.shipping);
console.log('Tax:', quote.money.tax?.amount ?? 0);
console.log('Total:', quote.money.total);

OrderQuote returns product_lines, booking_lines, digital_lines, shipping_lines, available shipping_methods and payment_methods, the selected payment_method_key, and one authoritative money breakdown. Monetary totals are always read from quote.money; tax details, when present, are in quote.money.tax.

Parameters

Name Type Description
id required string Cart ID to quote

Cart Checkout

POST /v1/storefront/carts/{id}/checkout
SDK: arky.client.eshop.cart.checkout()

Process payment and complete a cart. The SDK resolves the Store from its publishable key. The checkout response includes order_id, order number, a payment_action for any required next action, and the payment object.

const cart = await arky.client.eshop.cart.current();
await arky.client.eshop.cart.update({
id: cart.id,
product_items: [
  { product_id: 'prod_xyz789', variant_id: 'var_small', quantity: 2 }
],
shipping_method_id: 'ship_standard',
shipping_address: {
  name: 'Jane Doe',
  street1: '456 Contact Ave',
  city: 'New York',
  state: 'NY',
  postal_code: '10001',
  country: 'US'
},
forms: [
  {
    key: 'contact-info',
    entries: [
      { key: 'email', value: 'contact@example.com' },
      { key: 'firstName', value: 'John' },
      { key: 'lastName', value: 'Doe' }
    ]
  }
],
promo_code: 'SAVE10'
});

const result = await arky.client.eshop.cart.checkout({
id: cart.id,
payment_method_key: 'cash'
});

console.log('Order placed:', result.order_id, result.number);

Parameters

Name Type Description
id required string Cart ID
payment_method_key optional string Market payment method key such as 'cash' or 'credit_card'
return_url optional string Required for a positive card total; used after embedded checkout completes

Complete Checkout Flow

import { initialize, mountCheckoutAction } from "arky-sdk/storefront";

const arky = initialize("arky_pk_...", {
	market: "us",
	locale: "en",
});

async function checkout() {
	await arky.eshop.cart.load();

	// 1. Quote the backend cart to show prices
	const quote = await arky.eshop.cart.quote({
		shipping_method_id: selectedShipping,
		shipping_address: shippingAddress,
		forms: [
			{
				key: "contact",
				entries: [
					{ key: "email", value: contactEmail },
					{ key: "firstName", value: contactFirstName },
					{ key: "lastName", value: contactLastName },
				],
			},
		],
		promo_code: promoCodeInput,
	});

	if (!quote) throw new Error("Cart quote is unavailable");
	console.log("Total:", quote.money.total);

	// 2. Checkout with the selected market payment method.
	const result = await arky.eshop.cart.checkout({
		payment_method_key: "credit_card",
		return_url: window.location.href,
	});

	if (result.payment_action.type === "stripe_embedded_checkout") {
		const mounted = await mountCheckoutAction(
			result.payment_action,
			"#stripe-checkout",
		);
		// Call mounted.destroy() when the checkout container is removed.
	}

	return result.order_id;
}
Tip

Use arky.eshop.cart.quote to show price breakdowns before the contact commits to purchase. Checkout returns the closed stripe_embedded_checkout | none action. Mount it with mountCheckoutAction; it carries the exact connected Stripe account context and short-lived client secret required by Stripe.js. The completion callback is presentation state; only a signed Stripe webhook settles payment. Return URLs must use HTTPS outside localhost or a literal loopback address; credentials are rejected and fragments are removed.

Availability

GET /v1/stores/{storeId}/services/availability
SDK: sdk.eshop.service.getAvailability()

Availability belongs to services because the contact is choosing schedulable service capacity. Reads use the provider’s compact per-local-day ProviderSchedule projection rather than scanning orders. Checkout transactionally creates authoritative OrderBooking records and reserves the same schedule buckets; cancellation releases them. The projection is rebuildable from bookings.

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