> ## Documentation Index
> Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Functions Overview

> Custom business logic for cart, shipping, payments, discounts, and order placement

# Functions

Functions let your app run custom business logic at well-defined points
in the cart → checkout → order-placement pipeline. Unlike
[Extensions](/extensions/overview) which add UI, functions return
declarative JSON — operations, rates, discounts, errors — that the
platform applies to the order on your behalf.

Functions are sandboxed **Javy dynamic-mode WASM** modules. You compile
them on your own machine with `lms function build` (which calls Javy /
QuickJS) and upload the pre-built `.wasm` to the platform — the server
validates the artifact and runs it during the cart-verify and
order-placement phases. See
[CLI Setup → Local Function Compilation](/getting-started/cli-setup#local-function-compilation)
for the full build/test/deploy flow.

## Function Types

<CardGroup cols={2}>
  <Card title="Cart Transform" icon="cart-shopping" href="/functions/cart-transform">
    Update unit prices, merge lines into bundles, or expand a single line
    into multiple. Surfaces as `cartTransformDiscount` + per-entry
    `cartTransformDiscounts[]`.
  </Card>

  <Card title="Discount" icon="tag" href="/functions/discount">
    Apply order / line-item / shipping discounts with app-supplied
    labels. Surfaces as `appDiscount` + `shippingDiscount` with per-entry
    arrays.
  </Card>

  <Card title="Shipping Rate" icon="truck" href="/functions/shipping-rate">
    Add custom shipping options alongside the merchant's zones. Customer
    can pick from either.
  </Card>

  <Card title="Payment Customization" icon="credit-card" href="/functions/payment-customization">
    Hide, rename, or reorder payment methods. Enforced server-side at
    order placement.
  </Card>

  <Card title="Delivery Customization" icon="box" href="/functions/delivery-customization">
    Hide, rename, or reorder the merchant's shipping zones. Enforced
    server-side at order placement.
  </Card>

  <Card title="Order Validation" icon="check" href="/functions/order-validation">
    Block the order entirely if it fails your rules — quantity caps,
    geo restrictions, compliance checks.
  </Card>

  <Card title="Fulfillment Constraints" icon="warehouse" href="/functions/fulfillment-constraints">
    Restrict which fulfillment locations can ship which lines. Blocks
    order placement if no location can fulfill a constrained line.
  </Card>

  <Card title="Local Pickup Options" icon="store" href="/functions/local-pickup-options">
    Offer in-store / curbside pickup at merchant-owned locations as a
    delivery option in checkout.
  </Card>

  <Card title="Pickup Point Options" icon="map-pin" href="/functions/pickup-point-options">
    Offer carrier-operated parcel lockers and partner pickup points
    (DHL, UPS, InPost) as a delivery option.
  </Card>
</CardGroup>

There are exactly **nine** dispatched WASM function types (the cards
above). A manifest may also declare declarative `fulfillment_location_rule`
entries for **order routing rules** — JSON matchers that would pick a
fulfillment location — but these are only **parsed** from the manifest;
there is currently no backend dispatcher/consumer, so they do not execute
at runtime yet. See [Order Routing Rules](/extensions/order-routing) for
the manifest format and match operators.

## Cross-cutting capabilities

<CardGroup cols={2}>
  <Card title="Input field selection" icon="filter" href="/functions/input-fields">
    Declare `inputFields` on a manifest entry to project the input down
    to only the REST fields your function needs. Faster dispatch, smaller
    WASM payloads.
  </Card>

  <Card title="Network access" icon="globe" href="/functions/network-access">
    Opt in with `network_access: true` plus an `allowed_hosts` allow-list
    to call external HTTP services from inside your function.
  </Card>
</CardGroup>

## Function Manifest

Declare functions in your app's `app.json` under `extensions.functions[]`:

```json theme={null}
{
  "handle": "my-app",
  "name": "My App",
  "version": "1.0.0",
  "extensions": {
    "functions": [
      {
        "type": "cart_transform",
        "handle": "vip-pricing",
        "title": "VIP per-line pricing",
        "entrypoint": "dist/cart-transform.wasm"
      },
      {
        "type": "shipping_rate",
        "handle": "weekend-pickup",
        "title": "Weekend Pickup",
        "entrypoint": "dist/shipping-rate.wasm"
      }
    ]
  }
}
```

| Field            | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                        |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`           | yes      | One of the nine dispatched types: `cart_transform`, `discount`, `shipping_rate`, `payment_customization`, `delivery_customization`, `order_validation`, `fulfillment_constraints`, `local_pickup_options`, `pickup_point_options`. (A manifest may also carry declarative `fulfillment_location_rule` entries, but those are parsed only and not yet dispatched — see [Order Routing](/extensions/order-routing).) |
| `handle`         | yes      | Unique handle within the app.                                                                                                                                                                                                                                                                                                                                                                                      |
| `entrypoint`     | yes      | Path to the compiled WASM module, relative to the install dir.                                                                                                                                                                                                                                                                                                                                                     |
| `title`          | no       | Display label in the merchant's app admin.                                                                                                                                                                                                                                                                                                                                                                         |
| `appId`          | no       | App id (defaults to the install folder name).                                                                                                                                                                                                                                                                                                                                                                      |
| `inputFields`    | no       | REST field selection tree — see [Input fields](/functions/input-fields).                                                                                                                                                                                                                                                                                                                                           |
| `network_access` | no       | `true` to enable outbound HTTP — see [Network access](/functions/network-access).                                                                                                                                                                                                                                                                                                                                  |
| `allowed_hosts`  | no       | Required when `network_access: true`. Hostname allow-list.                                                                                                                                                                                                                                                                                                                                                         |

## Execution Points

| Function Type             | Cart verification | Order placement | What it changes                                               |
| ------------------------- | :---------------: | :-------------: | ------------------------------------------------------------- |
| `cart_transform`          |         ✓         |        ✓        | Per-line price/title + bundle totals                          |
| `discount`                |         ✓         |        ✓        | Order / line-item / shipping discount rows                    |
| `shipping_rate`           |         ✓         |        ✓        | Adds custom shipping / local-pickup / pickup-point options    |
| `payment_customization`   |         ✓         |   ✓ (enforced)  | Filters/relabels payment methods; rejects hidden selections   |
| `delivery_customization`  |         ✓         |   ✓ (enforced)  | Filters/relabels shipping zones; rejects hidden selections    |
| `order_validation`        |         ✓         |        ✓        | Rejects the order with an error message                       |
| `fulfillment_constraints` |                   |        ✓        | Blocks lines with no eligible fulfillment location            |
| `local_pickup_options`    |      reserved     |     reserved    | Adds merchant-owned pickup locations as a delivery option     |
| `pickup_point_options`    |      reserved     |     reserved    | Adds carrier parcel-locker pickup points as a delivery option |

Functions that affect cart-time pricing or option lists fire on
cart verification (cart/checkout preview) for parity. `order_validation`
also runs at both points — it fires on cart verification (with
`step: 'cart'`) and again as the final gate at order placement (with
`step: 'review'`). `fulfillment_constraints` is a final-gate check at
order placement only.
`local_pickup_options` and `pickup_point_options` manifests are honored
today; the checkout consumer ships in the delivery-options
release.

## Common Input Shape

Every function receives a `cart` envelope with the same shape:

```typescript theme={null}
interface CartInput {
  items: Array<{
    id: string;             // lineItemId
    variantId: string;
    productId: string;
    title: string;
    quantity: number;
    price: number;          // Effective unit price (display currency)
    originalPrice: number;  // Compare-at unit price
  }>;
  totalPrice: number;       // Subtotal in display currency
  itemCount: number;        // Sum of quantities
  currency: string;         // e.g. "INR", "USD"
}
```

Different function types receive different extras (`destination`,
`paymentMethods`, `shippingAddress`, `customer`, `deliveryOptions`,
`discountCodes`) — see each type's page.

<Note>
  All monetary values are in **display currency units**, not cents.
  `price: 19.99` means ₹19.99 / \$19.99. Same convention for everything
  your function returns.
</Note>

## Output Format

Each function type has its own output. Browse the dedicated pages for the
full contract — quick reference:

| Type                      | Returns                                                                |
| ------------------------- | ---------------------------------------------------------------------- |
| `cart_transform`          | `{ operations: [update \| merge \| expand] }`                          |
| `discount`                | `{ discounts: [{ title, value, valueType, target, ... }] }`            |
| `shipping_rate`           | `{ rates: [{ name, price, description?, kind?, pickup? }] }`           |
| `payment_customization`   | `{ operations: [hide \| rename \| reorder] }`                          |
| `delivery_customization`  | `{ operations: [hide \| rename \| reorder] }`                          |
| `order_validation`        | `{ errors: [{ message, target?, lineId?, code? }] }`                   |
| `fulfillment_constraints` | `{ constraints: [{ lineId, allowedLocationIds, message? }] }`          |
| `local_pickup_options`    | `{ pickupOptions: [{ id, title, address, hours?, distance?, fee? }] }` |
| `pickup_point_options`    | `{ pickupOptions: [{ id, title, address, hours?, distance?, fee? }] }` |

## Persistence

For monetary outputs (`cart_transform` deltas, `discount` entries) the
platform persists **both**:

* Summed scalars on `additionalFields` (e.g. `appDiscount`,
  `shippingDiscount`, `cartTransformDiscount`) — backwards compatible.
* Per-entry arrays on `additionalFields` (e.g. `appDiscounts[]`,
  `shippingDiscounts[]`, `cartTransformDiscounts[]`) — used to render
  one row per app-supplied label on cart, checkout, order page, and
  email receipts.

Every entry is stamped with `appId` so the merchant can attribute
revenue back to your app in reporting.

## Testing

1. **Local sandbox** — `lms function test -f src/function.js -t <type> --input-file fixtures/cart.json` compiles your source locally and runs
   it against the hosted sandbox without persisting anything. The fastest
   way to iterate on cart-transform, shipping, payment, delivery, and
   order-validation logic.
2. **Pre-built artifact** — `lms function test --wasm dist/function.wasm`
   uploads a `.wasm` you've already compiled (useful in CI where you
   build once and reuse).
3. **Live storefront** — install your app into the
   [Apps developer portal](/getting-started/app-listing), then place a
   real order. The platform runs the same dispatch for both the cart
   preview and final order placement.

## Rate Limits & Constraints

* **Execution timeout**: per-function-type defaults (override via env):

  | Function Type            | Default timeout |
  | ------------------------ | --------------- |
  | `discount`               | 500 ms          |
  | `payment_customization`  | 500 ms          |
  | `cart_transform`         | 1 s             |
  | `order_validation`       | 1 s             |
  | `delivery_customization` | 1 s             |
  | `shipping_rate`          | 2 s             |

  All timeouts are clamped to a **5 s hard cap** server-side.
* **WASM size cap**: 256 KB compiled.
* **Output size cap**: 20 KB of JSON written to stdout. Functions that emit
  more are dropped per their `fallback` policy — the cart still ships, but
  with no effect from that function on this request.
* **Failure mode**: a function that times out or throws is dropped for
  that request. Other active functions in the same dispatch (subject to
  the per-shop caps below) still run. The customer never sees the error
  directly — it's recorded in the function's execution log, visible via
  `lms function logs <handle>`.

<Note>
  **WASM runtime limits.** Functions ship as Javy dynamic-mode WASM
  modules with a 256 KB compiled-WASM cap and a shared QuickJS provider
  loaded once per worker. The WASM source patterns and bundle-size
  constraints work for any standard Javy or AssemblyScript build.
</Note>

### Why 256 KB is enough

Functions compile in **Javy dynamic mode**: your JavaScript is bundled as
a thin stub (typically 1–4 KB) that imports the shared QuickJS runtime
("provider") at execution time. The provider is loaded once per worker
and reused across every function, so each compiled function only carries
your code — not a copy of the runtime.

For comparison: a 500-line discount function compiles to roughly 3 KB,
two orders of magnitude under the cap. If your function approaches
256 KB you're probably bundling unnecessary dependencies — strip them
out rather than asking for a higher cap.

## Active-Install Caps Per Shop

A store can have at most N active apps contributing functions of the same
type. The cap is enforced at install time — both merchant install
(`/apps/:appId/install`) and OAuth token exchange (`/apps/oauth/token`)
reject the install with HTTP 409 if it would push the store over the cap.

| Function Type            | Max active per shop |
| ------------------------ | ------------------: |
| `cart_transform`         |                   1 |
| `payment_customization`  |                   5 |
| `delivery_customization` |                   5 |
| `order_validation`       |                   5 |
| `shipping_rate`          |                   5 |
| `discount`               |                  25 |

The dispatch site runs every active function of a given type on every
cart verification / order placement — without these caps a store could end up
with compounded discounts, hidden payment methods, or unbounded
cart\_transforms. To install a new app of a type that's already at the cap,
uninstall an existing one first.

<Note>
  An app that declares functions across multiple types counts once per type
  toward the relevant cap. E.g. an app shipping one `cart_transform` and one
  `discount` function consumes one slot of each.
</Note>

## Best Practices

<AccordionGroup>
  <Accordion title="Keep functions fast">
    Cart / checkout latency is conversion-critical. Time-bounded
    work only — no carrier-API calls without aggressive caching.
  </Accordion>

  <Accordion title="Make outputs idempotent">
    Functions re-run on every cart change. Derive your output from the
    current input + config, not from cached deltas — otherwise you'll
    double-apply discounts or operations.
  </Accordion>

  <Accordion title="Always pass through `appId` info via `message`/`title`">
    Customer-facing labels (`message`, `title`, rate `name`) become
    the visible row in cart, checkout, and the order page. Use clear,
    branded text — "VIP: 15% off" beats "Discount applied".
  </Accordion>

  <Accordion title="Version with the app">
    App versioning + rollback is wired via
    `/apps/developer/:appId/versions/*`. Test new function logic on a
    staged version before promoting to production.
  </Accordion>
</AccordionGroup>
