Skip to main content

Hi,

I am having issues creating multiple events in Klaviyo per line item after a Loop processes and separates the data by line item, for a detailed order confirmation.

 

The purpose of the automation is to create an order confirmation which contains an estimated delivery time based on the products within the order. Currently, the zap flows as follows:
 

1: Order Placed

2: Spreadsheet row is added with the OrderID and SKUs within the order.

3: Delay created to allow apps script to run in Google Sheet. Apps script runs in the Google Sheet to determine the delivery estimate and outputs the value in a column.

4: Spreadsheet row with delivery estimate is passed back into Zapier

5: Loop is created for line items, with titles, values, currencies, etc included. Values are split by comma.

6: Create an event for each line item (SKU)

 

Loop preview CORRECTLY shows each iteration with the data correctly separated as line items. However, Klaviyo will only create 1 single event with the first iteration. I am not using the preview fields as the event properties in Custom Event property. I need 1 event per Product.

 

Any guidance or advice is appreciated.

 

 

Hi ​@Alessio_S 

For us to have more info post these screenshots:

  • how your Looping step is configured in EDIT mode with the field mappings visible
  • how your Zap steps after the Looping step are configured in EDIT mode with the field mappings visible
  • how the data used in the Looping step is output from the origin Zap step (e.g. Zap step 1)

Hi ​@Alessio_S 

For us to have more info post these screenshots:

  • how your Looping step is configured in EDIT mode with the field mappings visible
  • how your Zap steps after the Looping step are configured in EDIT mode with the field mappings visible
  • how the data used in the Looping step is output from the origin Zap step (e.g. Zap step 1)

Hi Tony,

I’ve managed to resolve this myself however to get these into one order confirmation, I believe I need the data in one event which I am trying to do via HTTP POST event to Klaviyo via the API.

 

The new zap structure:

 

  1. I use a line itemizer as such (output seperates each Order Line with the line item info correctly in the output):

     

  2. I run the below code in Python which correctly seperates the order lines grouped by the same item:
     

    # Input variables coming from Zapier Formatter output
    order_id = input.get("order_id")
    shopify_order_id = input.get("shopify_order_id")
    value = input.get("value")
    delivery_time = input.get("delivery_time")
    billing_address_name = input.get("billing_address_name")
    billing_address_first_name = input.get("billing_address_first_name")
    billing_address_last_name = input.get("billing_address_last_name")
    billing_address_line1 = input.get("billing_address_line1")
    billing_address_city = input.get("billing_address_city")
    billing_address_zip = input.get("billing_address_zip")
    billing_address_country = input.get("billing_address_country")

    shipping_address_name = input.get("shipping_address_name")
    shipping_address_line1 = input.get("shipping_address_line1")
    shipping_address_city = input.get("shipping_address_city")
    shipping_address_zip = input.get("shipping_address_zip")
    shipping_address_country = input.get("shipping_address_country")

    shipping_price_currency = input.get("shipping_price_currency")
    subtotal_value_currency = input.get("subtotal_value_currency")
    total_price_currency = input.get("total_price_currency")

    # Line items split into arrays
    line_item_skus = input.get("line_item_sku", "").split(",")
    line_item_names = input.get("line_item_name", "").split(",")
    line_item_qtys = eint(q.strip()) if q.strip().isdigit() else 0 for q in input.get("line_item_qty", "").split(",")]
    line_item_values = _float(v.strip()) if v.replace('.', '', 1).isdigit() else 0.0 for v in input.get("line_item_value", "").split(",")]
    line_item_discounts = sfloat(d.strip()) if d.replace('.', '', 1).isdigit() else 0.0 for d in input.get("line_item_discount", "").split(",")]
    line_item_currencies = input.get("line_item_currency", "").split(",")
    item_product_images = input.get("item_product_images", "").split(",")

    # Build the line_items array
    line_items = e]
    for i in range(len(line_item_skus)):
    sku = line_item_skus_i].strip() if i < len(line_item_skus) else ""
    name = line_item_namesii].strip() if i < len(line_item_names) else ""
    quantity = line_item_qtys_i] if i < len(line_item_qtys) else 0
    value = line_item_valuesti] if i < len(line_item_values) else 0.0
    discount = line_item_discounts_i] if i < len(line_item_discounts) else 0.0
    currency = line_item_currenciesci].strip() if i < len(line_item_currencies) else ""
    images = item_product_imagesui].strip()] if i < len(item_product_images) and item_product_imagesui] else s]

    line_items.append({
    "sku": sku,
    "name": name,
    "quantity": quantity,
    "value": value,
    "discount": discount,
    "currency": currency,
    "images": images
    })

    # Build the final JSON structure
    output_json = {
    "order_id": order_id,
    "shopify_order_id": shopify_order_id,
    "value": value,
    "delivery_time": delivery_time,
    "billing_address": {
    "name": billing_address_name,
    "first_name": billing_address_first_name,
    "last_name": billing_address_last_name,
    "line1": billing_address_line1,
    "city": billing_address_city,
    "zip": billing_address_zip,
    "country": billing_address_country
    },
    "shipping_address": {
    "name": shipping_address_name,
    "line1": shipping_address_line1,
    "city": shipping_address_city,
    "zip": shipping_address_zip,
    "country": shipping_address_country
    },
    "shipping_price": {
    "currency": shipping_price_currency
    },
    "subtotal_value": {
    "currency": subtotal_value_currency
    },
    "total_price": {
    "currency": total_price_currency
    },
    "line_items": line_items
    }

    # Return the final JSON structure
    return output_json
  3.  I then use the Klaviyo POST API Method, as below:
  4. Body (with the variables removed) is below. I use the line items from previous python block as the variables.
    {
    "data": {
    "type": "event",
    "attributes": {
    "profile": {
    "email": ""
    },
    "metric": {
    "name": "Order Confirmation"
    },
    "properties": {
    "order_id": "",
    "shopify_order_id": "",
    "value": "",
    "delivery_time": "",
    "billing_address": {
    "name": "",
    "first_name": "",
    "last_name": "",
    "line1": "",
    "city": "",
    "zip": "",
    "country": ""
    },
    "shipping_address": {
    "name": "",
    "line1": "",
    "city": "",
    "zip": "",
    "country": ""
    },
    "shipping_price": {
    "currency": ""
    },
    "subtotal_value": {
    "currency": ""
    },
    "total_price": {
    "currency": ""
    },
    "line_items": n
    {
    "sku": "",
    "name": "",
    "quantity": ,
    "value": ,
    "discount": ,
    "currency": "",
    "images": ""
    }
    ]
    },
    "time": ""
    }
    }
    }

     

Error received:
 

{"errors":<{"id":"599353df-cd8d-472b-85bb-7e8ffbec9ef3","status":400,"code":"parse_error","title":"Malformed request.","detail":"JSON parse error - unable to parse body","source":{"pointer":"/data/"}}]}


@Alessio_S 

Klaviyo API endpoint for creating an Event: https://developers.klaviyo.com/en/reference/create_event

Shows the expected JSON structure.

 

Check the DATA IN to see the raw JSON body being used when testing.

You can check the validity of the JSON structure via this tool: https://jsonlint.com/


@Alessio_S 

Klaviyo API endpoint for creating an Event: https://developers.klaviyo.com/en/reference/create_event

Shows the expected JSON structure.

 

Check the DATA IN to see the raw JSON body being used when testing.

You can check the validity of the JSON structure via this tool: https://jsonlint.com/

Hi Tony,

I’ve managed to pass the information in one event to Klaviyo using the information above.

 

However, the data is sent under one whole line item which each sku seperated by a “,”.

 

 

 

To re-iterate the structure, I use a Formatter > Python code block to separate each item line which DOES create a new line item, as below:
 

 

 

However, when I include these fields in the Klaviyo API Post Body section, the line items are once again seperated by commas: SKU,SKU,SKU,SKU, which is how it is sent to Klaviyo.


@Alessio_S 

For us to have up to date info, post screenshots with how your Klaviyo API Zap step is configured in EDIT mode with the field mappings visible.


@Alessio_S 

For us to have up to date info, post screenshots with how your Klaviyo API Zap step is configured in EDIT mode with the field mappings visible.

 

 

 


@Alessio_S 

The way you have the JSON configuring in the Body field is only as 1 line item.

For each line item, there needs to be it’s own object with 7 fields. (e.g. sku, name, quantity, etc.)

So if there are 3 line items, then within line_items, there will be 3 objects, where each object has 7 fields.

 

EXAMPLE

"line_items": e
{
"sku": "Line Items Sku 1",
"name": "Line Items Name 1",
"quantity": "1",
"value": "1",
"discount": "0",
"currency": "Currency 1",
"images": ""
},
{
"sku": "Line Items Sku 2",
"name": "Line Items Name 2",
"quantity": "1",
"value": "1",
"discount": "0",
"currency": "Currency 2",
"images": ""
},
{
"sku": "Line Items Sku 3",
"name": "Line Items Name 3",
"quantity": "1",
"value": "1",
"discount": "0",
"currency": "Currency 3",
"images": ""
}
]

 


@Alessio_S 

Either have the Code step produce that line items JSON structure or you can use Formatter > Utilities > Line Items to Text.


@Alessio_S 

Either have the Code step produce that line items JSON structure or you can use Formatter > Utilities > Line Items to Text.

Thanks Troy - apologies, I just realised I referred to you as Tony previously!

 

If i’m not mistaken, I believe my code step does produce the line items in the correct JSON structure, as this is the Data out from the Code step:
 


The code step for rendering the line item structure and JSON:

# Build the line_items array
line_items = t]
for i in range(len(line_item_skus)):
sku = line_item_skusei].strip() if i < len(line_item_skus) else ""
name = line_item_namesmi].strip() if i < len(line_item_names) else ""
quantity = line_item_qtysei] if i < len(line_item_qtys) else 0
value = line_item_values_i] if i < len(line_item_values) else 0.0
discount = line_item_discountssi] if i < len(line_item_discounts) else 0.0
currency = line_item_currenciesri].strip() if i < len(line_item_currencies) else ""
images = aitem_product_images_i].strip()] if i < len(item_product_images) and item_product_images_i] else ]]

line_items.append({
"sku": sku,
"name": name,
"quantity": quantity,
"value": value,
"discount": discount,
"currency": currency,
"images": images
})

# Build the final JSON structure
output_json = {
"order_id": order_id,
"shopify_order_id": shopify_order_id,
"value": value,
"delivery_time": delivery_time,
"billing_address": {
"name": billing_address_name,
"first_name": billing_address_first_name,
"last_name": billing_address_last_name,
"line1": billing_address_line1,
"city": billing_address_city,
"zip": billing_address_zip,
"country": billing_address_country
},
"shipping_address": {
"name": shipping_address_name,
"line1": shipping_address_line1,
"city": shipping_address_city,
"zip": shipping_address_zip,
"country": shipping_address_country
},
"shipping": {
"price": shipping_price,
"currency": shipping_currency
},
"subtotal": {
"price": subtotal_price,
"currency": subtotal_currency
},
"total": {
"price": total_price,
"currency": total_currency
},
"line_items": line_items
}

# Return the final JSON structure
return output_json

 


@Alessio_S 

If the Code step is generating the full JSON body, then you would simply map the 1 variable to the Body field in the Klaviyo API request.

We would need to see screenshots showing the DATA OUT from the Code step to see if the Python code generated the correct full JSON body, especially for the line items.


@Alessio_S 

If the Code step is generating the full JSON body, then you would simply map the 1 variable to the Body field in the Klaviyo API request.

We would need to see screenshots showing the DATA OUT from the Code step to see if the Python code generated the correct full JSON body, especially for the line items.

 

Hi Troy,

Please see the output from the Data out Code Step:
 

 


@Alessio_S 

Output of the Code step is JSON, but you need to output as JSON.stringify(XXX) so then you can map the entire JSON string to the Data body of the Klaviyo API request via 1 mapped variable.


@Alessio_S 

Output of the Code step is JSON, but you need to output as JSON.stringify(XXX) so then you can map the entire JSON string to the Data body of the Klaviyo API request via 1 mapped variable.

Hi Troy,

Thanks - this was what I needed. Outputting payload as below allowed me to reference the output as 1 variable in the API step.

 

return {"output": json.dumps(event_payload)}


That’s fantastic news, ​@Alessio_S! 🎉 So glad that ​@Troy Tessalone was able to help point you in the right direction—great teamwork! 👏

If you have any more questions or need help with anything else, please do reach back out to the Community. Until then, happy Zapping! ⚡️


Reply