Skip to main content
Fynn Functions allows developers to extend the behavior of backend logic. Here you will learn how to set up and use Fynn Functions.
This extension is currently in a closed beta phase. Please contact us to get access.

How does Fynn Functions work?

Fynn Functions allows you to write custom functions that respond to events in Fynn. For this, we provide various extension points that you can use to write custom logic. If one or more functions are registered for an extension point, they are executed when the corresponding event occurs. A context object is passed that contains information about the event, which could be a cart, for example. Within the function, you can then perform any actions, such as calling an external API. Each function must return one or more predefined operations at the end, which are then executed by Fynn.
Each extension point has different context objects and operations that you can use.

Runtimes

Each function is executed in an isolated environment limited to 5 seconds. Please note that the runtime of a function directly affects Fynn’s response time.

Functionality in Fynn Functions

Within Fynn Functions, you can use all JavaScript functions that are also available in the browser.

Extension Points

Fynn Functions currently supports the following extension points:
  • Checkout: checkout.cart.delivery, checkout.cart.cart_item_option

Add Shipping Costs

The checkout.cart.delivery extension point can be used to add shipping costs to the cart. If the price of the shipping costs is one-time, it is only calculated in the 1st invoice and is not recurring. Otherwise, the price of the shipping costs is calculated in every invoice.

Context Object

context
DeliveryContext

Operations

checkout:add_delivery
AddDelivery

Example

function run (input) {
    const countryCode = input?.deliveryCountryCode;
    const itemsCount = input?.cart?.items.length;

  if (itemsCount === 0) return [];

    if (countryCode === 'DE') {
        return [{
            __type: 'checkout:add_delivery',
            product: '14937550-26d0-454a-b4d4-64eabac67663'
        }];
    }

    if (countryCode === 'CH') {
        return [{
            __type: 'checkout:add_delivery',
            product: '5a7f267a-087b-4bdf-a620-79a4e2942545'
        }];
    }

    // more custom logic, e.g. by zip, best price, etc.

    return [];
}

Add Product Options

The checkout.cart.cart_item_option extension point can be used to display selection options in the cart on the product.
Checkout Options

Context Object

product
CartItemProductInput
context
CartItemInput

Operations

checkout:add_cart_item_option_set
AddCartItemOptionSet
Alternatively, product options can be added based on a custom attribute in the product.
checkout:add_custom_field_list:as_option_set
AddCustomFieldListAsOptionSet

Example

function run(input) {
  return [
    {
      __type: 'checkout:add_cart_item_option_set',
      product: '0ba377f0-d9e9-4338-a107-9209a6e0f1fb',
      name: 'from Issue',
      label: 'from Issue',
      options: [
        {
          label: 'No. 24',
          value: '24'
        },
        {
          label: 'No. 25',
          value: '25',
          preselected: true,
        },
        {
          label: 'No. 26',
          value: '26'
        },
      ]
    }
  ];
}

Register Function

To register a function, create a support ticket to get access to Fynn Functions.

Global Context Objects

export type CartItemProduct

export type CartPublicCustomerAddress = {
  id: string;
  firstName?: string;
  lastName?: string;
  companyName?: string;
  street: string;
  houseNumber?: string;
  zip: string;
  city: string;
  addition?: string;
  countryCode: string;
  costCentre?: string;
  vatId?: string;
}

export type CartPublicItem = {
  name: string;
  description?: string;
  quantity: number;
  type: 'product' | 'plan' | 'delivery';
  id: string;
  product: {
      id: string;
      number: string | null;
      customFields: Record<string, any>;
  },
  periods?: {
    contractPeriod: string;
    cancellationPeriod: string;
  }[],
  quantityDetails: {
    aggregationType: 'count' | 'count_unique' | 'max' | 'sum' | 'average' | 'last_value';
    unit: string;
    description?: string;
    quantityEditable: boolean;
  },
  price: {
    currencyCode: string;
    taxRate?: number;
    totalNetAmount: number;
    type: 'recurring' | 'instant_metered' | 'metered';
    calculationType: 'flat_fee' | 'per_unit' | 'tiered' | 'volume' | 'stair_step' | 'percentage';
    payInAdvance: boolean;
    freeUnits?: number;
    price: {
      amount?: number;
      items?: {
        from: number;
        to?: number;
        amount: number;
        flatAmount: number;
      },
      percentage?: number;
      fixedAmount?: number;
    };
    recurring?: {
      interval: 'day' | 'week' | 'month' | 'year';
      intervalCount?: number;
      trialPeriodDays?: number;
      recurringAmount?: number;
    }
  },
  optionSets: CartPublicItemOptionSet[];
}

export type CartPublicItemOptionSet = {
  label: string;
  name: string;
  options: CartPublicItemOption[];
}

export type CartPublicItemOption = {
  label: string;
  value: string | number | boolean;
  preselected: boolean;
  product?: string | null;
  pricePlan?: string | null;
}

export type CartDiscountDetails = {
  discount: {
    code: string;
    name: string;
    type: 'percentage' | 'fixed_amount';
    percentage?: number;
    fixedAmount?: string;
    frequency: 'once' | 'limited' | 'lifetime';
    frequencyInterval?: number;
  };
  totalAmount: string;
  totalNetBeforeDiscount: string;
};

export type CartPublicPrice = {
  amountDue: number;
  currencyCode: string;
  netAmount?: number;
  taxes?: {
    netAmount: number;
    taxAmount: number;
    rate: number;
  }[];
  discountDetails?: CartDiscountDetails;
}

export type CartPublicSettings = {
  allowCoupons: boolean;
  forceCompany: boolean;
  backButton?: {
    label?: string;
    url: string;
  };
  showDeliveryAddress: boolean;
}

export type CartPublic = {
  id: string;
  customer?: string;
  email?: string;
  invoiceAddress?: CartPublicCustomerAddress;
  deliveryAddress?: CartPublicCustomerAddress;
  items: CartPublicItem[];
  price: CartPublicPrice;
  completionDetails?: {
    invoice: {
      number: string;
      downloadLink: string;
      amount: string;
    } | null,
    payment: {
      reference: string | null;
      method: string;
      bankAccount?: {
        iban: string;
        bic: string;
        bankName: string;
        accountHolder: string;
        reference: string;
      },
      qrCode?: string;
    },
    subscription?: {
      number: string;
    },
    confirmationMessage?: string;
    backToProviderUrl?: string | null;
  },
  settings: CartPublicSettings;
}