Storeware Docs

Checkout functions

Type your checkout functions, and read the schemas and limits Storeware holds them to.

import { ... } from '@storeware/plugin-sdk/functions';

defineFunctions

Types an app's functions export, so each handler is checked against its kind.

function defineFunctions<T extends { [handle: string]: { [K in FunctionKind]: { kind: K; run: FunctionTypes[K]; }; }[FunctionKind]; }>(functions: T): { [H in keyof T]: T[H]['run']; }

FunctionKind

type FunctionKind = (typeof FUNCTION_KINDS)[number];

PaymentMethod

type PaymentMethod = (typeof PAYMENT_METHODS)[number];

FunctionLine

type FunctionLine = z.infer<typeof functionLine>;

BasketInput

type BasketInput = z.infer<typeof basketInput>;

DeliveryOption

type DeliveryOption = z.infer<typeof deliveryOption>;

DeliveryRatesInput

type DeliveryRatesInput = z.infer<typeof deliveryRatesInput>;

DeliveryRatesOutput

type DeliveryRatesOutput = z.infer<typeof deliveryRatesOutput>;

DiscountInput

type DiscountInput = z.infer<typeof discountInput>;

DiscountOutput

type DiscountOutput = z.infer<typeof discountOutput>;

PaymentMethodsInput

type PaymentMethodsInput = z.infer<typeof paymentMethodsInput>;

PaymentMethodsOutput

type PaymentMethodsOutput = z.infer<typeof paymentMethodsOutput>;

CartValidationInput

type CartValidationInput = z.infer<typeof cartValidationInput>;

CartValidationOutput

type CartValidationOutput = z.infer<typeof cartValidationOutput>;

FunctionTypes

NameTypeDescription
discount(input: DiscountInput) => DiscountOutput | Promise<DiscountOutput>
delivery_rates(input: DeliveryRatesInput) => DeliveryRatesOutput | Promise<DeliveryRatesOutput>
payment_methods( input: PaymentMethodsInput, ) => PaymentMethodsOutput | Promise<PaymentMethodsOutput>
cart_validation( input: CartValidationInput, ) => CartValidationOutput | Promise<CartValidationOutput>

FUNCTION_KINDS

const FUNCTION_KINDS: readonly ['discount', 'delivery_rates', 'payment_methods', 'cart_validation']

PAYMENT_METHODS

The payment methods a function can hide or reorder. Platform level on purpose: card is every card and wallet Stripe offers, on_account is paying later on a business's terms, crypto is stablecoin payment.

const PAYMENT_METHODS: readonly ['card', 'on_account', 'crypto']

FUNCTION_CPU_MS

CPU time one call may use, in milliseconds.

const FUNCTION_CPU_MS: 25

FUNCTION_WALL_MS

Wall time one call may take, in milliseconds, waiting included.

const FUNCTION_WALL_MS: 250

MAX_FUNCTION_OUTPUT_BYTES

The largest answer a function may give, as JSON, in bytes.

const MAX_FUNCTION_OUTPUT_BYTES: number

functionLine

One line of the basket, as every kind sees it.

const functionLine: z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>

basketInput

What every kind is given: the basket, who is buying, and where it goes.

const basketInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>

deliveryOption

const deliveryOption: z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>

deliveryRatesInput

const deliveryRatesInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; options: z.ZodArray<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>>; }, z.core.$strip>

deliveryRatesOutput

The options to offer, in order. An option left out is hidden. Only options the input named may appear, each once, so an id never changes and nothing is invented; offering new rates is [checkout.delivery_rates]'s job.

const deliveryRatesOutput: z.ZodObject<{ options: z.ZodArray<z.ZodObject<{ id: z.ZodString; title: z.ZodOptional<z.ZodString>; amount: z.ZodOptional<z.ZodNumber>; }, z.core.$strict>>; }, z.core.$strip>

discountInput

const discountInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>

discountOutput

const discountOutput: z.ZodObject<{ discounts: z.ZodArray<z.ZodObject<{ title: z.ZodString; target: z.ZodUnion<readonly [z.ZodLiteral<'order'>, z.ZodLiteral<'delivery'>, z.ZodObject<{ lines: z.ZodArray<z.ZodString>; }, z.core.$strict>]>; value: z.ZodUnion<readonly [z.ZodObject<{ percent: z.ZodNumber; }, z.core.$strict>, z.ZodObject<{ amount: z.ZodNumber; }, z.core.$strict>]>; }, z.core.$strict>>; }, z.core.$strip>

paymentMethodsInput

const paymentMethodsInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>

paymentMethodsOutput

The methods to offer, in order. A method left out is not offered, and refused if tried.

const paymentMethodsOutput: z.ZodObject<{ methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>

cartValidationInput

const cartValidationInput: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>

cartValidationOutput

const cartValidationOutput: z.ZodObject<{ errors: z.ZodArray<z.ZodObject<{ message: z.ZodString; lineId: z.ZodOptional<z.ZodString>; }, z.core.$strict>>; }, z.core.$strip>

FUNCTION_SCHEMAS

Each kind's input and output schema, by kind.

const FUNCTION_SCHEMAS: { readonly discount: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>; readonly output: z.ZodObject<{ discounts: z.ZodArray<z.ZodObject<{ title: z.ZodString; target: z.ZodUnion<readonly [z.ZodLiteral<'order'>, z.ZodLiteral<'delivery'>, z.ZodObject<{ lines: z.ZodArray<z.ZodString>; }, z.core.$strict>]>; value: z.ZodUnion<readonly [z.ZodObject<{ percent: z.ZodNumber; }, z.core.$strict>, z.ZodObject<{ amount: z.ZodNumber; }, z.core.$strict>]>; }, z.core.$strict>>; }, z.core.$strip>; }; readonly delivery_rates: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; options: z.ZodArray<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; description: z.ZodOptional<z.ZodString>; carrier: z.ZodOptional<z.ZodString>; amount: z.ZodNumber; }, z.core.$strip>>; }, z.core.$strip>; readonly output: z.ZodObject<{ options: z.ZodArray<z.ZodObject<{ id: z.ZodString; title: z.ZodOptional<z.ZodString>; amount: z.ZodOptional<z.ZodNumber>; }, z.core.$strict>>; }, z.core.$strip>; }; readonly payment_methods: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>; readonly output: z.ZodObject<{ methods: z.ZodArray<z.ZodEnum<{ card: 'card'; on_account: 'on_account'; crypto: 'crypto'; }>>; }, z.core.$strip>; }; readonly cart_validation: { readonly input: z.ZodObject<{ storeId: z.ZodString; currency: z.ZodString; lines: z.ZodArray<z.ZodObject<{ id: z.ZodString; productId: z.ZodString; variantId: z.ZodString; sku: z.ZodNullable<z.ZodString>; title: z.ZodString; variantTitle: z.ZodNullable<z.ZodString>; quantity: z.ZodNumber; unitPrice: z.ZodNumber; grams: z.ZodNullable<z.ZodNumber>; requiresShipping: z.ZodBoolean; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>>; subtotal: z.ZodNumber; buyer: z.ZodObject<{ customerId: z.ZodNullable<z.ZodString>; companyId: z.ZodNullable<z.ZodString>; email: z.ZodNullable<z.ZodString>; metafields: z.ZodRecord<z.ZodString, z.ZodUnknown>; }, z.core.$strip>; destination: z.ZodNullable<z.ZodObject<{ country: z.ZodString; region: z.ZodNullable<z.ZodString>; postalCode: z.ZodNullable<z.ZodString>; city: z.ZodNullable<z.ZodString>; }, z.core.$strip>>; discountCode: z.ZodNullable<z.ZodString>; delivery: z.ZodNullable<z.ZodObject<{ id: z.ZodString; type: z.ZodString; title: z.ZodString; amount: z.ZodNumber; }, z.core.$strip>>; channel: z.ZodEnum<{ web: 'web'; agent: 'agent'; }>; }, z.core.$strip>; readonly output: z.ZodObject<{ errors: z.ZodArray<z.ZodObject<{ message: z.ZodString; lineId: z.ZodOptional<z.ZodString>; }, z.core.$strict>>; }, z.core.$strip>; }; }

On this page