# GoKarla Documentation
> Concatenated documentation for AI agents. Sourced from gokarla.io/docs and the OpenAPI specification.
# Getting Started
> Onboard Karla and connect your commerce stack
## Getting Started
Source: https://gokarla.io/docs/guides/getting-started
# Getting Started
Create an account, connect your shop, and publish your tracking page for free.
Come back here when you're ready to unlock automatic shipment tracking and
advanced flows.
## Set up your account
Head to [portal.gokarla.io](https://portal.gokarla.io) and sign up. You'll
create your organization and set up your first shop. No credit card
required.
The portal walks you through connecting your shop and publishing your
tracking page. Most merchants are live within 30 minutes.
Once you're live, dive into any of the guides below — or [book a
demo](https://calendly.com/frederik-s/25min) to unlock automatic shipment
tracking and advanced features.
## What you get for free
Push orders into Karla from any connected shop — Shopify, Shopware,
WooCommerce, or your own backend via the public API.
A branded, customer-facing tracking page for your shop. Orders appear as
soon as they're placed. Shipment status updates are **not** automatic on the
free tier — customers see order details and can track manually via their
carrier.
Let customers report issues (damaged, missing, wrong item) directly from
their tracking page. You handle resolution manually in the portal.
## What unlocks with a paid plan
Connect any of [1,200+ carriers worldwide](/docs/guides/carriers/overview)
and Karla polls them for you — customers see live status, ETA, and delivery
events without ever leaving your tracking page.
Wire Karla into your own ESP (Klaviyo, Braze, HubSpot) or webhooks, and
trigger branded notifications on any shipment event. [See Notify guides
→](/docs/guides/notify/disable-carrier-emails)
Plug Resolve into your existing support stack (Zendesk, Gorgias, Freshdesk,
etc.) with automated claim handling and reason mapping. [See helpdesk
integrations →](/docs/guides/resolve/integrations/overview)
Configure full resolution journeys on your tracking page — automatic claims,
conditional routing, and self-service refund / reship flows. [See Tracking
Page docs →](/docs/guides/tracking-page/overview)
Shipment tracking, helpdesk integrations, and advanced resolution flows are
tailored to your volume and carriers. Grab 20 minutes with our team — we'll
show you what's possible and quote based on your setup.
[Book a demo →](https://calendly.com/frederik-s/25min)
## Go deeper
Campaigns, analytics, discounts, operations, and settings — everything your
team does day-to-day lives in the portal.
[Open the portal guide →](/docs/guides/portal/overview)
Embedding options, advanced configuration, multi-domain setups, and custom
branding for your tracking experience.
[See tracking page docs →](/docs/guides/tracking-page/overview)
Configure triggers and wire them into your own ESP — Klaviyo, Braze,
HubSpot, or plain webhooks.
[See notify guides →](/docs/guides/notify/disable-carrier-emails)
Advanced issue resolution — automatic claims, reason mapping, provider
integrations, and custom resolution flows.
[See resolve guides →](/docs/guides/resolve/overview)
Deep-dive each platform — Shopify, Shopware, WooCommerce — or go fully
headless with our public API.
[See shop integrations →](/docs/guides/shops/overview)
1,200+ supported carriers and per-carrier setup guides.
[Browse carriers →](/docs/guides/carriers/overview)
---
# Portal
> Campaigns, analytics, operations, discounts, the tracking page editor, and settings in the portal
## Overview
Source: https://gokarla.io/docs/guides/portal/overview
# Merchant Portal Guide
Welcome to the Karla Merchant Portal. This guide walks you through all portal sections and explains how to use them to get the most value out of your post-purchase experience.
You can read this guide end-to-end or jump directly to the sections relevant to your role.
:::tip Who should use what?
Different teams use different parts of the Karla Merchant Portal. Each section is tagged by role (Marketing, Operations, Management, Tech) to help you filter the content and focus on what's most relevant to you.
:::
## Portal Overview
The Karla Merchant Portal is your central place to manage everything related to your Karla setup — especially your tracking page, analytics & KPIs, settings, and integrations.
In the left-hand navigation, you'll find the main sections of the portal, in
the order they appear in the sidebar:
| Section | Description | Recommended For |
| -------------------------------------------------------------- | -------------------------------------------------------- | ---------------------- |
| [Home](#home-page-quick-snapshot) | Quick snapshot of your setup, metrics, and system health | All Users |
| [Campaigns](./campaigns) | Manage promotions shown on the tracking page | Marketing, Management |
| [Analytics](./analytics) | Track performance and engagement metrics | Marketing, Management |
| [Operations](./operations) | Monitor shipments, orders, delivery times, and triggers | Operations, Management |
| [Discounts](./discounts) | Manage the discount codes your campaigns can apply | Marketing |
| [Resolve](./resolve) | Handle delivery issues and view claims analytics | Operations, Support |
| [Tracking Page](./tracking-page) | Design, preview, and publish your tracking page | Marketing, Tech |
| [Customise Text](./customise-text) | Override tracking page copy, with multi-language support | Marketing |
| Notify: [Email templates](/docs/guides/notify/email-flows) | Create and manage the email flows Karla sends for you | Marketing |
| Notify: [Custom triggers](/docs/guides/notify/custom-triggers) | Fire time-based events into Klaviyo for stuck shipments | Marketing, Tech |
| [Settings](./settings) | Manage integrations, API keys, and configuration | Tech, All Users |
## Home Page: Quick Snapshot
On the **Home** page, you'll find a quick overview of your setup, including:
- Key metrics from the last 30 days
- A snapshot of your current campaigns
- Connected integrations
- System health
- Helpful articles related to your setup
## What's Next?
In the following sections of this guide, we'll walk through each portal area in detail so you know exactly how to use it in your day-to-day work.
---
## Campaigns
Source: https://gokarla.io/docs/guides/portal/campaigns
# Campaigns
The **Campaigns** section in the portal lets you manage every promotion that
appears on your Karla tracking page — creating new campaigns, editing existing
ones, segmenting who sees what, and measuring impact.
**Recommended for:** Marketing, Management
## Campaign types
Karla supports three campaign types, each optimized for a different objective:
### Main promotions
Flexible content blocks with custom messaging and a call-to-action button.
Perfect for straightforward offers that don't require specific product focus.
**Use for:** discounts, referral programs, seasonal messaging, brand
announcements.
### Product promotions
Highlight one or more products directly on the tracking page — with images,
names, prices, and per-product CTAs.
**Use for:** cross-selling, upselling, product recommendations.
On Shopify, the same active **manual** product promotion also feeds the
[one-click post-purchase upsell](/docs/guides/shops/post-purchase-upsell) by
default — so keeping a live manual product promotion is part of enabling that
checkout surface.
Products can be added two ways:
- **Automatically (Shopify integration)** — pulled from your Shopify catalog;
just search and select.
- **Manually** — enter title, image, price, description, and translations
yourself. Works for any catalog, even if it's not synced.
### Banner promotions
Mobile-only campaigns that appear at the top of the tracking page. Short,
high-impact, time-sensitive.
**Use for:** flash sales, limited-time offers, mobile-focused messaging.
## How a promotion is structured
Every promotion includes:
| Element | Description |
| ------------------------ | --------------------------------------------------------- |
| **Internal name** | Used only for internal organization |
| **Segment** | Determines which customers see the promotion |
| **Start & end date** | Optional — useful for scheduled or time-limited campaigns |
| **Title & subtitle** | The main message customers see on the tracking page |
| **CTA (call-to-action)** | Button label and destination URL |
| **Discount** | Optional — if the promotion includes an incentive |
| **Translations** | Campaigns can be localized for different languages |
| **Image** | A visual that supports the promotion |
After adding or updating content, **save** the promotion.
### Creating and managing promotions
- Create a **new promotion** from scratch, or **clone an existing one** to
reuse its setup.
- Promotions can be **live or disabled**, so you can prepare campaigns in
advance.
- Multiple promotions can run simultaneously using segmentation.
- Use **Preview** to open the promotion inside the
[Tracking Page editor](./tracking-page), where
a device selector switches between desktop and mobile rendering. Preview is
only available for promotions that are currently live — it stays disabled for
disabled ones.
## Discounts and segmentation
To get the most out of your campaigns, you'll use **discounts** (to drive
action) and **segments** (to target the right audience). Both are managed in
the portal.
### Creating discounts for Karla campaigns
Karla uses dedicated discounts that are intended specifically for the tracking
page experience.
#### Step 1: Create the discount in your shop
First, create the discount in your shop backend (Shopify, Shopware, etc.):
- Define the discount type (percentage, fixed amount, free shipping, etc.)
- Set the value and rules as usual
This ensures the discount is valid and usable at checkout.
#### Step 2: Add the discount to the Karla Portal
To use a discount in a Karla campaign, register it in the
[Discounts](./discounts) section — an internal title, the code exactly as it
exists in your shop system, its type, and its value. Once saved, the discount
becomes available in any campaign via a dropdown.
:::warning Important
If a discount is not added to the Discounts section first, it won't be
available for use in campaigns.
:::
### Using discounts in campaigns
After adding a discount to the portal:
- Select it in any **basic**, **product**, or **banner** campaign.
- This keeps discounts organized, avoids duplicates, and enables
[campaign attribution](/docs/guides/tracking-page/attribution) via the
discount code.
## How segmentation works
Segmentation lets you show different campaigns to different customer groups —
e.g., a 10% off offer to first-time customers but premium product suggestions
to VIPs.
### Where segments come from
- Karla pulls segments from **Klaviyo** and/or **Shopify**.
- Segments are **not** created in the Karla Portal directly — define them in
Klaviyo/Shopify, and they appear in Karla after a brief sync.
- When creating or editing a campaign, you'll see all synced segments in a
dropdown.
- **Shopify**: both **order tags and customer tags** become segments with the
prefix `Shopify.tag.` — Karla reads them from the same webhook payload and
treats them identically. See
[Customer Segments via Order Tags](/docs/guides/shops/shopify#customer-segments-via-order-tags)
for the full pattern, including how to use Shopify Flow to drive tags from
customer attributes, line items, or Shopify Customer Segments.
- **Shopware**: customer/order tags, customer group, and sales channel are
emitted with the prefixes `Shopware.tag.`, `Shopware.customer_group.`, and
`Shopware.sales_channel.`. See
[Order segments](/docs/guides/shops/shopware#order-segments) for details.
- **Klaviyo**: lists and segments become `Klaviyo.list.` and
`Klaviyo.segment.`.
### When segments are evaluated
Karla evaluates segments at these moments:
1. **At order placement** — all sources are read.
2. **At every order update in Shopify** — Karla re-reads order tags from the
webhook payload. Tags added after placement (e.g., by Shopify Flow) land
on the order immediately.
3. **At order fulfillment** — all sources are re-checked. This is the final
check that decides which campaign the tracking page shows.
:::info Klaviyo segment refresh
Klaviyo segments are cached per customer for seven days to avoid hammering the
Klaviyo API. The two moments that actually decide which campaign is shown —
**order placement** and **order fulfillment** — bypass that cache and always
ask Klaviyo directly, so both reads are fresh regardless of the cache. Plain
order updates in between are cache-first: they reuse the cached membership and
only call Klaviyo when nothing is cached yet. Shopify tags have no cache — they
reflect the current order state on every webhook.
:::
:::tip Important
The segments determined **at fulfillment** are what ultimately decide which
campaign is shown. If a customer's segments change after fulfillment, the
order is not updated. This is intentional — it keeps campaign assignments
consistent for a given shipment.
:::
### Fallback and multi-match behavior
- **Default fallback** — if the customer matches no live campaign segment, the
**default campaign** is shown.
- **Multiple matches** — when a customer matches several live campaigns, Karla
picks the **first match found**. Since order segments aren't explicitly
ordered, this produces a degree of randomness — which is actually useful for
natural A/B testing across overlapping segments.
## Campaign recipes by segment
A starter library of campaign ideas you can adapt to your brand. Copy,
translate, and tune as needed.
### New customers
**Objective:** encourage first-time buyers to make a repeat purchase.
| Recipe | Title (EN) | CTA |
| ----------------------- | --------------------------------------------------- | --------------------- |
| Next-order discount | "Welcome to [Brand]! Enjoy 10% off your next order" | "Claim your discount" |
| Newsletter signup | "Join & enjoy 10% off your next order!" | "Sign up now" |
| Accessories discount | "Complete your look — get €10 off accessories" | "Shop accessories" |
| Free gift with purchase | "A special gift just for you!" | "Claim your gift" |
**Other ideas:** free shipping on the next order if placed within 7 days;
exclusive welcome bundle with bestsellers; free downloadable style guide or
product care tips.
### Repeat customers
**Objective:** strengthen loyalty and increase repeat purchase frequency.
| Recipe | Title (EN) | CTA |
| ------------------------- | ---------------------------------------------- | --------------------- |
| Subscriptions | "Never run out — subscribe & save 15%!" | "Subscribe now" |
| App install | "Exclusive in-app deals just for you!" | "Get the app" |
| WhatsApp delivery updates | "Track your order instantly on WhatsApp!" | "Sign up for updates" |
| Referral program | "Refer [Brand] & get €10 off your next order!" | "Refer now" |
| Membership sign-up | "Members save more! Join today" | "Join the club" |
**Other ideas:** early access to new collections or limited-time offers.
### Product-based targeting
| Recipe | Title (EN) | Campaign type |
| ------------------------- | ------------------------------------------------------ | ----------------- |
| High-spending customers | "Luxury add-ons to elevate your style" | Product promotion |
| Price-conscious customers | "Great deals under €20 — shop now!" | Product promotion |
| Cross-category upsell | "Have you already tried XYZ? We think you'll love it!" | Product promotion |
| Product bundles | "Save big with our exclusive bundles!" | Product promotion |
### Food & beverage — recipe guides
**Objective:** encourage repeat purchases by adding value.
| Title (EN) | CTA |
| ------------------------------------------------ | -------------- |
| "Exclusive recipe guide — free with your order!" | "Download now" |
### Discount-loving customers
**Objective:** encourage higher spending by offering tailored discounts.
| Title (EN) | CTA |
| ---------------------------------------------------- | --------------- |
| "More savings, just for you! Grab an extra 20% off!" | "Shop the sale" |
## Best practices
- **Keep campaigns focused** — one message, one CTA per promotion.
- **Don't stack too many promotions** at the same time on the same segment —
it dilutes impact.
- **Use segmentation for relevance** — a targeted campaign outperforms a
generic one every time.
- **Use Karla-specific discount codes** so attribution stays clean. Keep them
unique, time-limited, and unshareable (e.g., `KARLA-WELCOME-DEC` instead of
`SAVE10`).
- **Allow time for new segments to sync** from Klaviyo/Shopify before
launching a dependent campaign.
- **Use high-quality images** (minimum 800×800px, `.webp` preferred) and keep
copy concise and action-oriented.
- **A/B test systematically** — change one variable at a time, run tests for
at least 7 days, and aim for >100 orders per variant before drawing
conclusions.
## Measure what you launched
Every campaign reports impressions, click-through rates, and revenue in the
portal. How accurately Karla can attribute those conversions depends on which
attribution method you're using — dig into the details in
[Campaign attribution](/docs/guides/tracking-page/attribution).
---
## Analytics
Source: https://gokarla.io/docs/guides/portal/analytics
# Analytics
The **Analytics** section helps you understand how customers interact with your tracking page and how this interaction translates into engagement and revenue. It gives you the insights needed to evaluate performance and make informed decisions about your campaigns.
**Recommended for:** Marketing, Management
## The Analytics sub-pages
**Analytics** expands in the sidebar into its own dashboards. The sections below describe what you'll find across them:
| Sub-page | What it covers |
| ------------------- | ---------------------------------------------------------------- |
| **Overview** | High-level summary and the headline KPIs |
| **Reach** | How many customers open the tracking page, and how often |
| **Engagement** | Clicks and interactions, broken down by widget and campaign type |
| **Purchases** | Repurchases, revenue, and the individual orders behind them |
| **Campaign Stats** | Per-campaign performance |
| **Klaviyo Metrics** | Klaviyo flow performance (alpha — visible for some shops only) |
## Analytics Overview
In the **Overview** dashboard, you'll find a high-level summary of your tracking page performance. The most important KPIs are highlighted at the top.
---
## Key Tracking Page KPIs
### Tracking Page Open Rate
This metric shows the **percentage of customers who opened the tracking page** within a selected time period (e.g., last 30 days).
:::info Important
This is **not** an email open rate. It measures how many customers actually landed on the tracking page — independent of your email provider.
:::
### Engagement Rate
The engagement rate reflects how actively customers interact with the tracking page, including:
- Clicks on campaigns
- Interactions with page elements
A higher engagement rate usually indicates that your content is relevant and well-placed.
### Repurchases
Repurchases show how many customers made an additional purchase **directly after interacting with the tracking page**.
- Repurchases are **session-based**
- The purchase happens in the same session in which the tracking page was opened
- Karla is recognized as the source
### Revenue from Repurchases
This metric shows the **total revenue generated by repurchases** that originated from the tracking page.
Together, **repurchases** and **repurchase revenue** help quantify the business impact of your post-purchase experience.
---
## Click Insights
To better understand what customers interact with, clicks are broken down into different widget types.
### Promotional Widgets Clicks
These include clicks on:
- Main promotions
- Product promotions
- Banner promotions
They indicate how attractive and relevant your campaigns are.
### "Where Is My Order?" (WISMO) Clicks
These include clicks on functional tracking elements such as:
- Shipment status
- Order summary
- Carrier links
It's normal for these clicks to be higher than campaign clicks, as customers primarily visit the tracking page to check their delivery status.
---
## Campaign Performance Breakdown
Analytics also show how different campaign types perform:
- Main promotions
- Product promotions
- Banner promotions
This helps you understand which formats work best for your audience.
---
## Segment Performance
You can see how different **customer segments** interact with campaigns. For example:
- Which segment engages most with a promotion
- Which segment engages least with a promotion
This insight can help you optimize segmentation and campaign targeting.
---
## Purchase Details
For deeper analysis, open the **Purchases** dashboard. Here you can:
- Filter repurchases
- See individual orders that originated from the tracking page
- Check whether a discount code was applied
Additional data includes:
| Field | Description |
| -------------------- | ---------------------------------------------------------- |
| **Landing site** | The page the customer visited before making the repurchase |
| **Order attributes** | Indicators confirming Karla as the source of the purchase |
---
## Additional Insights
The Analytics section also provides supporting metrics such as:
- Average views per customer
- Device type (mobile vs desktop)
- Referral source
These insights are useful for optimizing:
- Mobile vs desktop tracking page layouts
- Campaign placement and design
---
## How to Use Analytics Effectively
- Focus on **trends over time**, not single data points
- Use analytics to guide campaign iteration
- Combine engagement and revenue metrics to evaluate impact
Analytics are most powerful when used as a decision-making tool, not just for reporting.
---
## Operations
Source: https://gokarla.io/docs/guides/portal/operations
# Operations
The **Operations** section gives you transparency into your delivery performance and shipment data. It helps you monitor how shipments are progressing, how carriers perform, and where attention may be needed.
**Recommended for:** Operations, Management
**Operations** expands in the sidebar into four sub-pages:
- **Shipments**
- **Delivery Times**
- **Orders**
- **Triggers**
**Shipments** and **Orders** each open on a **List** tab — a searchable, filterable table of individual records — with an **Analytics** tab alongside it for the aggregated dashboard. **Delivery Times** and **Triggers** are analytics dashboards only.
---
## Shipments
The **Shipments** sub-page shows all shipments that Karla has captured for your shop within a selected time frame.
### What You Can Do Here
- View all shipments for a specific period
- Filter shipments by:
- Date range
- Customer segments (e.g., Shopify tags)
- Shipment phase
- Delivery status
### What Insights You Get
- Carrier performance at a glance (e.g., normal vs delayed shipments)
- Comparison across different carriers
- Visibility into shipment outcomes such as returns
### Shipment Table
The shipment table lists all shipments matching your filters and allows you to:
- Identify specific delivery issues
- Filter for special cases (e.g., returned shipments)
- Open an individual shipment to inspect its full event history
To export shipment data as a **CSV file** for your operations or logistics team, switch to the **Analytics** tab and export from the dashboard there.
---
## Delivery Times
The **Delivery Times** sub-page focuses on how long your shipments take to arrive.
### What You Can See
- Average delivery time in:
- Business days
- Calendar days
- Delivery time development over time
- Performance based on different timestamps, such as:
- Order placed → delivered
- Order fulfilled → delivered
These views help you understand carrier performance more accurately.
### Carrier & Country Comparison
If you ship to multiple countries, you can:
- Compare delivery times by country
- See how different carriers perform in each region
This makes it easier to identify where delivery performance differs and where improvements may be needed.
### Delivery Targets & Anomalies
If you have a target delivery time (e.g., delivery within 5 days), you can:
- Check whether this target is being met
- See what percentage of shipments exceed the threshold
You'll also see **anomalies**, such as shipments that have not been delivered after several days. These shipments may require:
- Follow-up with the carrier
- Proactive communication with customers
---
## Orders
The **Orders** sub-page provides additional insights based on your shop data.
### What You'll Find Here
- Order distribution (e.g., by country)
- Orders that used discounts
- An orders table with individual entries
You can also open specific tracking pages directly from this view to see what customers experienced.
---
## Triggers
The **Triggers** sub-page shows delivery-related notification triggers sent to your systems (e.g., Klaviyo).
### What This Includes
- Trigger types such as:
- In transit
- Out for delivery
- Delivered
- Distribution shown as percentages or counts
- Filtering by carrier
This helps you understand:
- How often certain delivery events occur
- Which carriers generate which triggers
- What information is being sent to your messaging tools
---
## How to Use Operations Effectively
| Sub-page | Best Used For |
| ------------------ | -------------------------------------------------------- |
| **Shipments** | Day-to-day monitoring and issue spotting |
| **Delivery Times** | Evaluating carrier performance and delivery expectations |
| **Orders** | Connecting delivery insights with shop data |
| **Triggers** | Understanding delivery event communication |
Together, these views help you stay proactive, transparent, and informed about your delivery operations.
---
## Discounts
Source: https://gokarla.io/docs/guides/portal/discounts
# Discounts
The **Discounts** section is your shop-wide list of discount codes that Karla
campaigns can use. Register a code here once, and it becomes available in any
Main, Product, or Banner promotion — where it is automatically applied when
customers interact with the promotion on your tracking page.
**Recommended for:** Marketing
:::important Karla does not create discount codes
A discount in Karla is a reference to a code that already exists in your shop
system. Always create the code in your shop backend (Shopify, Shopware, etc.)
first — that is what makes it valid at checkout. If the code doesn't exist in
your shop, customers will see an error when they try to redeem it.
:::
## Creating a discount
Open **Discounts** in the sidebar and click **Create**. Each discount has five
fields:
| Field | Description |
| -------------- | ------------------------------------------------------------------------------ |
| **Title** | Internal title for your own reference — it won't be shown to the customer |
| **Type** | Scope of the discount: **Order**, **Product**, or **Shipping** |
| **Code** | The code applied to the shopping basket — exactly as it exists in your shop |
| **Value Type** | **Percentage** or **Fixed Amount** |
| **Value** | The discount amount, interpreted according to the value type (e.g., 15 or €15) |
Save the discount and it appears in the Discounts table, which lists the
title, code, value, and type of every discount. Click any row to edit or
delete it.
:::tip Use Karla-specific codes
Create codes dedicated to the tracking page (e.g., `KARLA-WELCOME-DEC` rather
than `SAVE10`). Unique codes keep [campaign
attribution](/docs/guides/tracking-page/attribution) clean and prevent
uncontrolled sharing.
:::
## Using discounts in campaigns
Every campaign form — Main, Product, and Banner promotions — has a
**Discount** dropdown listing all registered discounts by title and code. Pick
one (or **(No discount)**) per promotion:
- The selected code is automatically applied when customers interact with the
promotion, so they don't need to type it at checkout.
- The same discount can be reused across multiple campaigns.
- Because the code is tied to the campaign, redemptions feed
[campaign attribution](/docs/guides/tracking-page/attribution) — you see
which campaign drove which orders.
If a code you expect to use is missing from the dropdown, it hasn't been added
to the Discounts section yet — register it there first.
For the full campaign workflow — types, segmentation, and measurement — see
[Campaigns](./campaigns).
---
## Resolve
Source: https://gokarla.io/docs/guides/portal/resolve
# Resolve
The **Resolve** section is especially useful for understanding why customers report delivery issues and how those issues evolve over time.
:::info
Resolve is an optional feature included in certain Karla packages. Contact your account manager if you're interested in enabling it.
:::
---
## Previewing the Resolve Flow
The **Preview** option allows you to see exactly how the Resolve flow looks from a customer's perspective.
### What the Preview Is For
- Understanding the customer experience
- Reviewing the steps customers go through when reporting an issue
- Validating copy, structure, and flow
:::warning Do not submit from the preview
The preview embeds your **live** Resolve flow against a seeded demo order — it
is not a sandbox and there is no dry-run mode. Clicking through the steps to
inspect them is fine, but **completing a submission creates a real claim**,
with every side effect a real claim has: helpdesk tickets, claim webhooks,
notification events, and claim automation rules.
If you want to test end to end, do it deliberately and clean up the resulting
claim afterwards.
:::
This is helpful if you're unsure how the Resolve flow currently looks or want to walk internal teams through it.
---
## Claims Analytics
The **Claims Analytics** section gives you detailed insights into all claims submitted by customers via Resolve.
### Quick Insights Overview
At the top, you'll see a high-level summary, such as:
- Total number of claims in a selected time period
- Number of affected orders
This helps you distinguish between:
- Many claims for few orders (indicating serious issues)
- Evenly distributed, isolated cases
### Claim Breakdown & Patterns
Claims are analyzed across multiple dimensions to help you understand root causes:
| Dimension | Description |
| ------------------------- | ------------------------------------------------------------- |
| **Top issue types** | E.g., damaged items, not received, delivery problems |
| **Preferred resolutions** | What customers most often ask for (e.g., refund, replacement) |
| **Shipment phase** | When claims are submitted (e.g., in transit vs delivered) |
For example, a high number of claims at the _delivered_ stage often indicates issues discovered upon arrival.
### Geographic & Carrier Insights
You can also see:
- Where claims are coming from geographically
- How claims are distributed across shipment phases
This helps identify:
- Regional patterns
- Carrier-related issues
- Market-specific challenges
### Product-Level Insights
Resolve also shows which products are most frequently affected by claims. This can highlight:
- Fragile products
- Packaging issues
- Recurring quality problems
These insights can be useful beyond operations — for example, for product or fulfillment improvements.
---
## Claims Table
At the bottom of the section, you'll find a **detailed claims table** with all individual claims submitted via Resolve.
### What You Can Do Here
- Review individual claim details
- Filter and analyze specific cases
- Export the data as a **CSV file** for:
- Deeper analysis
- Sharing with operations, logistics, or product teams
---
## How to Use Resolve Effectively
- Use the **Preview** to understand and explain the customer experience — without submitting
- Monitor **Claims Analytics** regularly to spot trends early
- Look for repeated issues across products, carriers, or regions
- Use exports to align internal teams on recurring problems
Resolve is most powerful when used **proactively**, not just reactively.
---
## Claim Automation
Admins can configure **automated claim resolution** under
**Settings → Claim Automation** — separate from the Claims analytics view
above.
- Build **ordered rule sets** with logic checks on claim reason, resolution
preference, claimed value, and shipment status.
- Choose **Automate** (refund or reorder in your shop) or **Manual** (route to
your team) per rule.
- Control whether automated outcomes still create **helpdesk tickets**.
Karla applies **platform safety gates** (stock, address, duplicate order, shop
errors) even when a rule matches. See
[Claim automation](/docs/guides/resolve/claim-automation) for the full guide.
---
---
## Tracking Page
Source: https://gokarla.io/docs/guides/portal/tracking-page
# Tracking Page
The **Tracking Page** section is the visual editor for your customer-facing
tracking page. You see a live preview of the page, change layout, style, and
content in the settings panel next to it, and publish when you're happy — no
code required.
**Recommended for:** Marketing, Tech
To learn what the tracking page itself does for your customers, start with the
[Tracking Page guide](/docs/guides/tracking-page/overview). This page covers
the editor in the portal.
## Preview and Production
Two tabs at the top switch between editing and inspecting:
- **Preview** shows your current draft on an example order — including changes
you haven't published yet. A phase selector switches the example between
**Shipped** and **Delivered**, and a language selector renders the page in
any of your supported languages.
- **Production** shows what customers see right now. Search for a specific
order, or pick a customer segment to load a real tracking page from that
segment, and use **Open live page** to open it in a new browser tab.
In both tabs, a device selector switches the frame between desktop, tablet,
and mobile — useful because layout and some settings differ per device.
## The settings panel
In the Preview tab, the **Settings** panel sits next to the preview (use the
**Settings** button to show or hide it). Clicking a widget in the preview
jumps straight to its settings. The panel contains:
### Customise colours
Opens the **Brand Colors** dialog, where you manage the colour palette all
other sections pick from. Define your brand colours once here, then map them
to widgets, banners, and buttons below.
### Banner Promotion
Only shown while previewing mobile. Sets the colours (background, text,
button, and button text) of the mobile banner shown when a
[banner promotion campaign](./campaigns#banner-promotions) is active.
### Notification Banner
A dismissible announcement bar on the tracking page. Toggle it on, choose
which countries see it (leave empty for all — useful for shipping notices that
only affect certain destinations), optionally show a CTA with a link URL, and
map its colours. The banner text itself is edited in
[Customise Text](./customise-text).
### Widget layout
The list of widgets on your tracking page, in display order:
- Toggle widgets on or off, and drag them to reorder. Mobile and desktop keep
separate arrangements, so switch the device selector to arrange both.
- Click a widget to open its per-widget settings.
- **Main Promotion** and **Product Promotion** are always available — they
appear on the page whenever a matching [campaign](./campaigns) is active.
- Some widgets are enabled by the Karla team on request — if a widget's toggle
is locked, contact us to enable it.
For what each widget shows to your customers, see the
[Tracking Page guide](/docs/guides/tracking-page/overview).
### Style
Page-wide look and feel: font, button corner radius and font weight, widget
corner radius, and the page background colour.
### Order Finder
The standalone page where customers look up their order by order number and
zip code. Configure its background (a palette colour or an image with
alignment) and colours, and use **Preview Order Finder** to open it.
### Advanced
- **Order identifier** — which order reference (order number, order name, or
external ID) is shown in the order summary and shipment tabs.
- **Allowed Domains** — the domains permitted to embed your tracking page.
### Page Metadata
The browser-facing details of the page: title, description, and favicon URL.
## Saving and publishing
Edits stay local until you publish. As soon as you change something, a bar
appears with **Discard** and **Save**:
- **Discard** reverts to the last published state.
- **Save** publishes after a confirmation — changes are applied to all your
tracking pages in production immediately.
:::tip Check both devices before publishing
Widget arrangement is stored separately for mobile and desktop. After
reordering or toggling widgets, flip the device selector to confirm both
layouts look right, then publish once.
:::
---
## Customise Text
Source: https://gokarla.io/docs/guides/portal/customise-text
# Customise Text
The **Customise Text** section lets you rewrite the copy on your tracking page
to match your brand voice — every label, banner message, and FAQ entry, in
every language you support.
**Recommended for:** Marketing
## How it works
The editor is a table of text keys. Each row is one piece of tracking page
copy; the placeholder shows Karla's default text. Type your own text to
override it, or clear a field to fall back to the default. Nothing you leave
untouched changes.
Tabs group the keys by where they appear on the page:
- **Tracking widget** — shipment status labels (ordered, shipped, delivered,
returns) and the copy around the shipment journey.
- **FAQ** — up to five question-and-answer pairs shown on the tracking page.
- **Reviews** — title and success message of the reviews widget, if enabled
for your shop.
- **Notification banner** — the banner content and CTA text configured in the
[Tracking Page editor](./tracking-page).
- **Order finder** — the title, field labels, and button of the order lookup
page.
## Languages
The first column edits your English copy. Click **Add Language** to add a
column for another supported language and translate each key; remove a
language column to drop its overrides. Customers see the language matching
their tracking page locale, falling back to defaults for anything you haven't
overridden.
## Saving
Use **Save** in the top-right corner to publish your changes, and **Preview**
to jump into the [Tracking Page editor](./tracking-page) and see them on an
example order.
---
## Settings
Source: https://gokarla.io/docs/guides/portal/settings
# Settings
The **Settings** section is where you manage all account-level and technical configurations related to your Karla setup. Most customers only need to visit this section occasionally.
**Recommended for:** Tech, All Users
:::warning
Some settings can impact live integrations, so changes should be made thoughtfully.
:::
---
## API Keys
The **API Keys** section allows you to generate an API key for direct access to the Karla API.
:::info Good to Know
- This is mainly relevant if you are using custom or advanced integrations
- Standard Shopify or Klaviyo integrations usually do **not** require an API key
- If you plan to use the Karla API, please contact the Karla team before setting this up
:::
---
## Integrations
The **Integrations** section is one of the most important parts of the Settings area. This is where Karla connects to your existing systems.
### Shop Integration (e.g., Shopify)
If you use Shopify, this section allows you to:
- Manage the connection between your shop and Karla
- View or update the API key generated by the Karla Shopify app
- Ensure your store is correctly connected
### Messaging & CRM Integrations (e.g., Klaviyo, HubSpot)
You can also manage integrations with messaging and CRM tools such as:
- Klaviyo
- HubSpot
- Other supported notification systems
Here you can configure:
| Setting | Description |
| --------------------------- | --------------------------------------------------------------------------- |
| **Delivery event triggers** | Which delivery events trigger notifications |
| **Klaviyo segments** | Whether Klaviyo segments are used |
| **Shipment events** | Which shipment events are sent (e.g., shipped, out for delivery, delivered) |
These settings control how delivery updates and events are communicated to customers.
### Claim Automation
Under **Settings → Claim Automation**, admins configure **rule-based claim
resolution** — ordered logic that automatically refunds or reorders qualifying
Resolve claims in your shop.
| Setting | Description |
| --------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Enable claim automation** | Master switch for automated refund and reorder |
| **Notification mode** | Create a helpdesk ticket on automated outcomes, or resolve silently |
| **Rules** | Ordered rule set with conditions (reason, preference, value, shipment status) and Automate or Manual actions |
Only **admin** users can edit these settings. Full setup, example rule sets,
and safety gates are documented in
[Claim automation](/docs/guides/resolve/claim-automation).
---
## Shop Profile
The **Shop Profile** contains general information about your brand and shop within Karla. This includes:
- Shop URL and admin URLs
- Organization or brand name
- Logo
- Brand colors
Keeping this information up to date ensures a consistent brand experience across the tracking page and communications.
---
## Users & Access
The **Users & Access** section allows you to manage who can access the Karla Portal. Here you can:
- Add new users
- Assign roles and permissions
- Control which shops users can access (if you manage multiple shops)
:::info Important
Newly added users are emailed an invitation automatically. They sign in with
that email address via a magic link — there is no password to share. If an
invite doesn't arrive, you can still send them the portal link directly; the
sign-in works the same way.
:::
---
## Webhooks
The **Webhooks** section allows you to create webhooks for advanced use cases. These can be used to:
- Send Karla events to other systems
- Build custom workflows or integrations
This section is typically used by technical teams.
---
## Important Note on Settings
Some changes in the Settings section can affect live data, integrations, or customer communication. If you're unsure about a setting or its impact, we recommend contacting the **Karla team** before making changes.
---
## Final Tip
Most standard setups require minimal changes in Settings once everything is configured. The section is designed to give flexibility while keeping your setup stable.
---
# Tracking Page
> Customer-facing tracking experience
## Overview
Source: https://gokarla.io/docs/guides/tracking-page/overview
# Tracking Page
Real-time shipment status, your brand, marketing moments when engagement is at
its highest, and self-service resolution when something goes wrong — all on
one page, tuned for every device.
## Try it
Click around a live tracking page with sample data. What your customers see
after checkout — minus the prod order.
## What you get
Live status from 1,200+ carriers worldwide, normalized into a single
timeline with ETA, delivery windows, and exception alerts.
Colors, typography, logo, copy, layout — configurable in the [Merchant
Portal](https://portal.gokarla.io). Multi-language out of the box.
Basic, product, and banner campaigns targeted by customer segment. The
tracking page is the most-opened post-purchase surface — use it.
When something goes wrong, customers flow straight into a resolve step
without leaving the page or opening a support ticket.
## Widgets
Every tracking page is assembled from **widgets** — self-contained blocks you
switch on, reorder, and style without writing code. Mobile and desktop keep
separate arrangements, so the order that works on a phone doesn't have to be
the order that works on a wide screen.
| Widget | What it shows | When it appears |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Tracking Events** | The core of the page: shipment status, progress bar, the full carrier event timeline, and delivery forecasts. Optional extras include an FAQ and a report-an-issue entry into [Resolve](/docs/guides/resolve/overview). | On for every shop — this is the widget customers come for. |
| **Order Summary** | Order number, package contents, and prices — subtotal, delivery, discount, total. Prices can be hidden entirely. | Whenever it's switched on. |
| **Delivery Address** | The recipient's delivery address as confirmed at checkout. | Whenever it's switched on. |
| **Tracking Number** | Carrier name, tracking number, and a link to the carrier's own tracking page. | Whenever it's switched on and the shipment has a tracking number. |
| **Main Promotion** | A flexible promotion block — image, headline, optional discount code, and a call-to-action. Comes in overlay-card, feature-card, and gift-reveal styles. | Only while a [main promotion campaign](/docs/guides/portal/campaigns) is active for the customer's segment. |
| **Product Promotion** | A product carousel with images, names, prices, and per-product calls-to-action — your cross-sell surface. | Only while a product promotion campaign is active. Products the customer already bought in this order are filtered out automatically. |
| **Reviews** | A star-rating prompt. A five-star rating forwards the customer to your Trustpilot review page. | Once every shipment in the order is delivered without incident. Contact us to enable it for your shop. |
| **AI Agent** | A floating AI assistant that answers delivery questions directly on the page. | When the Karla AI agent is enabled for your shop. It floats above the page instead of occupying a slot in the layout. |
On desktop, **Delivery Address**, **Tracking Number**, and **Reviews** are
grouped into a single **Delivery Info** block that you position as one unit.
Two page-level banners frame the widget stack:
- **Notification Banner** — a pinned announcement bar above the widgets with
an optional call-to-action link. You can restrict it to specific delivery
countries — useful for carrier disruptions or holiday shipping notices.
- **Banner Promotion** — a mobile-only campaign banner at the very top of the
page for short, time-sensitive offers. Like the other promotions, it
appears only while a [banner campaign](/docs/guides/portal/campaigns) is
active.
:::tip Configure it in the portal
Everything above lives in the [Merchant Portal](https://portal.gokarla.io)
under **Tracking Page**: switch widgets on or off, drag to reorder them
separately for mobile and desktop, and select any widget to adjust its
options, colors, and text — with a live preview beside you.
:::
## Where to next
- [Integrate in your shop](/docs/guides/tracking-page/integrate-in-your-shop) —
drop the widget into your site in under a minute.
- [Campaign attribution](/docs/guides/tracking-page/attribution) — measure
what the tracking page drives at checkout.
- [Portal → Campaigns](/docs/guides/portal/campaigns) — configure and
segment the promotions that appear here.
---
## Integrate in your shop
Source: https://gokarla.io/docs/guides/tracking-page/integrate-in-your-shop
# Integrate in your shop
Tracking pages embed into your shop website through the Karla
[Browser SDK](/docs/platform/browser-sdk) — a single script tag plus a
container div.
:::tip Shopify shops
If you're on Shopify, skip this guide — our Shopify app ships a theme
extension that handles the embed for you. Follow
[Advanced: Setting up your own Tracking Page template](/docs/guides/shops/shopify#advanced-setting-up-your-own-tracking-page-template)
to wire it into a dedicated template.
**Never** add the tracking widget to your default page template — it will
override every page using that template.
:::
## Embed the tracking widget
Add a container div and the bundle script to the page where you want the
tracking widget to render:
```html
```
Replace `my-shop-slug` with your own shop slug (find it in the
[portal](https://portal.gokarla.io/) under your shop profile).
For all supported script attributes, order lookup methods, debug options, and
advanced configuration, see the [Browser SDK](/docs/platform/browser-sdk)
reference.
## Test your embed
Once the page is published (e.g. `https://your-shop-domain/tracking`), add
order identifiers as URL parameters to preview a real order:
- ZIP code lookup: `https://your-shop-domain/tracking?orderNumber=00001&zipCode=10119`
- Token-based lookup: `https://your-shop-domain/tracking?orderNumber=00001&token=abc123`
See the [Browser SDK](/docs/platform/browser-sdk) for all supported lookup
methods.
:::tip Tokens unlock extra actions on the order
When you link to the tracking page with a **token** instead of a ZIP code,
Karla treats the visitor as authenticated for that specific order. We
reserve advanced, order-scoped operations (things like cancellation flows
and similar sensitive actions) for token-authenticated sessions, and the
set of capabilities behind the token keeps growing over time.
Token lookup is **enabled by default** on every shop (Shopify and others),
and every notification Karla sends — including the tracking page URL in
shipping emails — already carries the token for that order. You can also
retrieve a token-protected URL for any order through our public
[API](/docs/api-reference), so you can embed secure deep links in your own
emails, flows, or support tools.
:::
## Order finder
If you want a standalone finder page (where shoppers enter their own order
details), set `data-starter-page="finder"`:
```html
```
Other starter pages (`order-tracking` — the default, `tracking-updates`,
`resolve`, `global`) and the full attribute list are documented in the
[Browser SDK](/docs/platform/browser-sdk).
## Using the API directly
If you'd rather build your own tracking UI from scratch, see the
[API reference](/docs/api-reference).
---
## Campaign attribution
Source: https://gokarla.io/docs/guides/tracking-page/attribution
# Campaign attribution
Attribution answers one question: **which orders did your tracking-page
campaigns generate?** Karla answers it by tagging every campaign link with
query parameters, capturing those parameters in your shop when the customer
buys, and matching the result back to the campaign in your analytics.
## How attribution works
1. A campaign (main, product, or banner promotion) is shown on your tracking
page, in a notification email, or on the thank-you page.
2. When the customer clicks the call-to-action, Karla has already appended its
attribution parameters to the target URL — no setup needed on the link
side.
3. Your storefront **captures** the parameters. This is the only step where
you have choices to make — see [capture paths](#capture-paths).
4. When the order is created, the captured parameters are stored on the Karla
order as `order_analytics`.
5. Karla matches the `campaign` value back to the campaign and reports
impressions, clicks, orders, and revenue in the
[portal analytics](#where-attribution-shows-up).
```mermaid
flowchart LR
A["Campaign shown (tracking page, email, thank-you page)"]
B["Customer clicks CTA URL carries karla_* params"]
C["Storefront captures params (pixel, SDK, plugin, or API)"]
D["Order created stored as order_analytics"]
E["Campaign matched reported in Analytics"]
A --> B --> C --> D --> E
```
Discount codes are an independent, complementary signal that skips steps 2–3
entirely — see [discount code attribution](#discount-code-attribution).
## The attribution parameters
Every campaign call-to-action link carries these query parameters:
| Parameter | Example value | Meaning |
| ---------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `ref` | `karla` | Marker present on every Karla-originated link. See [source markers](#source-markers) for variants. |
| `karla_source` | `trackpages` | The surface the click came from. |
| `karla_medium` | `product_promotion` | The promotion type: `basic_promotion`, `product_promotion`, or `banner_promotion`. |
| `karla_campaign` | `9f1c6a7e-3b2d-4e8f-9a10-1234567890ab` | The campaign's unique ID — this is what links the order to the exact campaign. |
Product-promotion links that are rendered on a specific order's tracking page
additionally carry the **originating order**, so you can trace a repeat
purchase back to the order whose tracking page produced it:
| Parameter | Meaning |
| ------------------------- | -------------------------------------- |
| `karla_order_external_id` | Platform ID of the originating order. |
| `karla_order_number` | Order number of the originating order. |
| `karla_order_name` | Display name of the originating order. |
Two things worth knowing:
- **Karla never overrides existing parameters.** If a target URL you
configured already contains `karla_source` (or any other parameter), your
value wins.
- **The parameters describe the campaign, never the shopper.** They contain
no user data, which keeps the privacy story simple — see the consent notes
under each capture path.
### Source markers
The `ref` parameter distinguishes which Karla surface produced the click:
| Marker | Set on | Captured by |
| -------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `ref=karla` | All campaign links on tracking pages and in notifications. | All capture paths. |
| `ref=karla-thankyou` | Call-to-action links of the [thank-you page promotion](/docs/guides/shops/shopify) in the Karla Shopify app. | Browser SDK global mode. The Shopify pixel records the `karla_*` parameters those links also carry. |
| `ref=karla-lounge` | Links from the Karla Lounge brand-deals page. | Browser SDK global mode (also as legacy `source=karla-lounge`). |
## Capture paths
The parameters only matter if something in your storefront records them and
attaches them to the order. All four paths below produce the same result — an
`order_analytics` record on the Karla order — so pick whichever fits your
stack. They can coexist; the first captured attribution wins.
### Shopify app pixel
The Karla Shopify app ships a
[web pixel](https://shopify.dev/docs/apps/build/marketing-analytics/build-web-pixels)
that captures the parameters on landing and sends them to Karla only when a
checkout completes.
- Enable it once in the Karla app under **Settings → Campaign Attribution**
(pixel toggle, consent requirement, optional browse tracking).
- The pixel stores the parameters in **session storage** (key
`karla_attribution`) — scoped to the current tab, cleared when it closes,
first click wins within the session. Alongside the `karla_*` parameters it
records `ref` only when the value is exactly `karla`.
- **Consent** is yours to configure: **No consent required** (default — the
parameters are non-PII and short-lived), **Analytics consent required**, or
**Marketing consent required**. With a consent level set, the pixel stays
idle until your privacy banner reports that consent.
- **Browse tracking** (beta) buffers viewed product IDs in local storage (key
`karla_browse`) and always requires **analytics consent**, independent of
the attribution setting. The buffer is purged as soon as an order
completes, consent is withdrawn, or the feature is turned off.
### Browser SDK global mode
If you embed the tracking page with the [Browser SDK](/docs/platform/browser-sdk),
you can load it site-wide in `global` mode:
```html
```
On every page load it checks the URL for attribution parameters and writes
them as **cart attributes** via Shopify's `/cart/update.js`:
`_karla_source`, `_karla_campaign`, `_karla_medium`, `_karla_captured_at`,
`_karla_landing_url`, `_karla_landing_path`, `_karla_referrer`,
`_karla_version`. Shopify copies cart attributes onto the order, where Karla
reads them back into `order_analytics`.
- **First click wins per cart** — once `_karla_source` is on the cart, later
visits don't overwrite it.
- Accepts `karla_source` or the legacy markers `ref`/`source` equal to
`karla` or `karla-lounge`.
- The landing URL is stripped of sensitive query parameters (tokens, emails,
click IDs, and ~40 more) and truncated to Shopify's 255-character
attribute limit. Nothing is written to cookies or browser storage — the
data lives on the cart itself.
- Shopify-only: the mode deactivates quietly when `/cart.js` doesn't exist.
### Shopware plugin
The Karla Shopware plugin forwards Shopware's native affiliate tracking:
`affiliateCode` and `campaignCode` on the order are translated into the
canonical `source` and `campaign` fields when the order syncs to Karla. See
the [Shopware guide](/docs/guides/shops/shopware) for plugin setup.
### Direct API
On headless or custom stacks, capture the parameters yourself (URL params,
session, server-side) and send them in the `order_analytics` field when you
create or update the order via the
[Orders API](/docs/platform/orders#attribution):
```json
{
"order_analytics": {
"source": "trackpages",
"campaign": "9f1c6a7e-3b2d-4e8f-9a10-1234567890ab",
"medium": "product_promotion",
"landing_url": "https://shop.example.com/products/foo?ref=karla",
"landing_path": "/products/foo",
"referrer": "https://track.gokarla.io/",
"captured_at": "2026-08-07T10:30:00Z"
}
}
```
Use the canonical keys `source` (required for attribution), `campaign`,
`medium`, `landing_url`, `landing_path`, `referrer`, and `captured_at` — they
map 1:1 to what the other capture paths produce. The legacy alias keys
`affiliate_code` and `campaign_code` are accepted and rewritten to `source`
and `campaign`. Strip secrets and PII from `landing_url` before sending; the
Browser SDK's sanitizer is a good reference for what to remove.
This path gives you full control (server-side, immune to ad blockers, works
on any platform) at the cost of owning the capture logic yourself.
## Discount code attribution
Attach a discount code to a campaign in the
[portal](https://portal.gokarla.io) and any order using that code is
attributed to the campaign — no parameters involved, so it works on every
platform and survives ad blockers, disabled JavaScript, and cross-device
checkouts.
**Best practices:**
- Keep the code **exclusive to the campaign** — shared or leaked codes
(coupon sites, social media) inflate attribution.
- Create **unique codes per campaign** and rotate or time-limit them.
- Keep codes simple but distinctive — e.g. `KARLA-WELCOME-DEC` instead of
`SAVE10`.
**Verification:** filter orders by discount code in your platform (Shopify:
**Orders → Filter by discount code**; WooCommerce: **Orders → Filter by
coupon**).
Discount attribution complements the parameter-based paths: parameters catch
non-discount campaigns, codes catch customers who saw a campaign but
converted later on another device.
## Verify your setup
Walk the chain once end-to-end:
1. **Click a campaign.** Open your tracking page for a test order, click the
campaign's call-to-action, and check the address bar: you should see
`ref=karla`, `karla_source`, `karla_medium`, and `karla_campaign`.
2. **Check the capture.**
- _Pixel:_ in the storefront tab, open dev tools → **Application →
Session Storage** and look for the `karla_attribution` key.
- _Browser SDK global mode:_ add something to the cart, then open
`/cart.js` in the browser — the `attributes` object should contain
`_karla_source` and friends.
3. **Place a test order** in that same session, then confirm the attribution
arrived: fetch the order via the API and check `order_analytics`, or open
the order in the portal.
4. **Check the reporting.** The campaign's numbers appear in
**Analytics → Purchases** and **Analytics → Campaign Stats** (allow some
time for processing).
**When something is missing:**
- **No parameters on the click** — the campaign target URL already carried
its own `karla_*` parameters (yours win), or you tested a link outside a
campaign.
- **Pixel captured nothing** — the pixel is disabled, the configured consent
level wasn't granted by your banner, or the link only carried a marker the
pixel ignores (it records `ref` only for `ref=karla`).
- **SDK captured nothing** — the store isn't Shopify (`/cart.js` missing),
or the cart already carries an earlier `_karla_source` (first click wins).
- **Order has no attribution** — the customer checked out in a different
browser, device, or session than the click; parameter-based attribution
can't bridge that gap, discount codes can.
- **Attribution looks too high** — a campaign discount code is circulating
outside Karla surfaces.
## Where attribution shows up
- **Analytics → Purchases** — attributed orders and revenue per campaign.
- **Analytics → Campaign Stats** — impressions, click-through rate, and
conversion per campaign; this is also what
[A/B tests](/docs/guides/portal/campaigns) read.
- **Order data** — `order_analytics` on the order via the
[Orders API](/docs/platform/orders#attribution).
- **Karla MCP** — the `get_order_campaigns` tool returns the campaigns shown
for a specific order, so you can query attribution from
[Claude or any MCP client](/docs/platform/ai/mcp).
:::info Attribution method affects accuracy
Parameter-based attribution undercounts cross-device journeys; discount
codes overcount when codes leak. For A/B tests, prefer parameter or API
attribution, run tests for at least 7 days, and treat ~100+ orders per
variant as the minimum for significance.
:::
## Related
- [Campaigns in the portal](/docs/guides/portal/campaigns) — create and
manage campaigns.
- [Orders API](/docs/platform/orders#attribution) — full `order_analytics`
reference.
- [Browser SDK](/docs/platform/browser-sdk) — embed options, including
global mode.
---
# Notify
> Email flows, custom triggers, and notification integrations
## Disable carrier emails
Source: https://gokarla.io/docs/guides/notify/disable-carrier-emails
# Carrier Emails & How To Switch Them Off
:::note
If you want to prevent DHL or other carriers from sending email notifications to your customers, the strategy depends heavily on the type of relationship and integration your shop has with your carriers, fulfillment providers, or label creation services. Here’s a breakdown based on the different setups:
:::
## Summary of Possible Solutions
| Setup Description | How to Block Carrier Emails |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Direct Contract with DHL** | Contact DHL to disable emails; configure the API integration to manage notifications. |
| **Shopify Shops using 247APPS** | To disable customer notifications in Shopify apps like easyDHL, go to the app's settings, select "Shipping," and turn off "DHL Notifications." |
| **Fulfillment Provider Manages Process** | Request the provider to handle notifications / use their platform to block carrier emails. |
| **Fulfillment Provider with Third-Party Label Service** | Use third-party service (e.g., Sendcloud) to manage notifications - block DHL emails through platform settings. |
| **Custom API Configurations** | Prevent sending email data to the carrier API to avoid triggering notifications. |
## 1. Shop with a Direct Contract with DHL and a Direct Contact Person
- **DHL Contract Settings**: Shops with a direct contract with DHL often have a dedicated account manager or contact person at DHL. These shops can request specific adjustments to the service, including blocking or disabling DHL’s default email notifications to customers.
- **Solution**: Contact DHL’s account manager to ask them to disable the customer email notifications for tracking, delivery, or any other updates.
- **Consideration**: It may be possible to configure DHL’s API or integration to suppress carrier notifications by customizing webhook or email settings. However, this can depend on the account type and the specific services negotiated.
## 2. Shopify Shops using 247APPS (easyDHL, easyDPD, easyHermes, easy GLS)
- **Switching off emails via the Shopify app:** For Shopify apps like easyDHL and easyDPD, you can control customer notifications through the app settings (depending on your plan). To disable notifications, go to your easyDHL app → Settings → Shipping → DHL Notifications.

## 3. Shop with a Fulfillment Provider in Charge of the Entire Fulfillment Process
- **Fulfillment Provider’s Role**: When a shop uses a third-party fulfillment provider the provider often takes responsibility for the logistics, including the shipment notifications. In this setup, DHL might still be the carrier, but the provider will manage the tracking and customer notifications.
- **Solution**: Request the fulfillment provider to manage notifications directly. Providers may allow merchants to control the email notifications that customers receive or suppress any emails from DHL.
- **Fulfillment Software Integration**: The fulfillment provider may have a platform that allows stores to configure email notifications, which can override the carrier’s default notifications. The shop can ensure that only its system (e.g., through Shopify or Klaviyo) sends customer updates.
## 4. Shop with a Fulfillment Provider and Third-Party Label Creation Service
- **Third-Party Label Creation Services (e.g., Sendcloud)**: Many fulfillment providers use third-party label creation services to streamline logistics. These services generate the shipping labels, and the carrier (like DHL) processes the shipments. If these services are integrated with the shop's system, they can override the carrier’s default notifications.
- **Sendcloud & Similar Providers**: If Sendcloud or another label provider is used, they often provide an interface to control email notifications. You can configure it to suppress any notifications from DHL, ensuring that all updates come from your shop directly.
## 5. Other Possibilities and Considerations
- **Email Suppression at the API Level**: Some eCommerce platforms allow merchants to control what information gets passed to the carrier API, such as email addresses. If the email address is not sent to DHL via the API, DHL will not be able to send notifications.
- A workaround here could also be defining a default email-address(e.g. dhl@gokarla.io) for all carrier notifications instead of sending real customer data to the carrier.
---
## Webhooks
Source: https://gokarla.io/docs/guides/notify/webhooks
# Webhooks
Webhooks let Karla push events to your systems in real time. Instead of
polling for changes, your endpoint receives a POST request the moment
something happens — a shipment goes out for delivery, a parcel is delivered,
a claim is submitted, etc.
## Create a webhook in the portal
The easiest way is the [Karla Portal](https://portal.gokarla.io): go to
**Settings → Webhooks**, add a destination URL, pick the events you care
about, and save. Karla starts delivering events immediately.
That's all most merchants need. The rest of this page covers the programmatic
setup and the details of how to build a receiver that stays secure and
reliable.
## Create a webhook via the API
If you'd rather manage webhooks from code (CI pipelines, infra-as-code,
multi-shop setups), use the [Webhooks API](/docs/api-reference).
**`POST /v1/shops/{slug}/webhooks`**
```bash
curl -X POST https://api.gokarla.io/v1/shops/your-shop-slug/webhooks \
-u your-username:your-private-api-key \
-H "Content-Type: application/json" \
-d '{
"enabled_events": [
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered"
],
"secret": "41013bd9-9072-42cd-9902-66da38361be9",
"description": "Shipment Deliveries",
"status": "active",
"url": "https://example.com/my-webhook-endpoint"
}'
```
```javascript
const response = await fetch(
"https://api.gokarla.io/v1/shops/your-shop-slug/webhooks",
{
method: "POST",
headers: {
Authorization:
"Basic " +
Buffer.from("your-username:your-private-api-key").toString("base64"),
"Content-Type": "application/json",
},
body: JSON.stringify({
enabled_events: [
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered",
],
secret: "41013bd9-9072-42cd-9902-66da38361be9",
description: "Shipment Deliveries",
status: "active",
url: "https://example.com/my-webhook-endpoint",
}),
},
);
const webhook = await response.json();
console.log(webhook);
```
```python
import requests
from requests.auth import HTTPBasicAuth
webhook_data = {
"enabled_events": [
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered"
],
"secret": "41013bd9-9072-42cd-9902-66da38361be9",
"description": "Shipment Deliveries",
"status": "active",
"url": "https://example.com/my-webhook-endpoint"
}
response = requests.post(
'https://api.gokarla.io/v1/shops/your-shop-slug/webhooks',
json=webhook_data,
auth=HTTPBasicAuth('your-username', 'your-private-api-key')
)
webhook = response.json()
print(webhook)
```
```php
[
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered"
],
"secret" => "41013bd9-9072-42cd-9902-66da38361be9",
"description" => "Shipment Deliveries",
"status" => "active",
"url" => "https://example.com/my-webhook-endpoint"
];
curl_setopt($ch, CURLOPT_URL, 'https://api.gokarla.io/v1/shops/your-shop-slug/webhooks');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($webhook_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_USERPWD, 'your-username:your-private-api-key');
$response = curl_exec($ch);
curl_close($ch);
$webhook = json_decode($response, true);
print_r($webhook);
?>
```
```ruby
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.gokarla.io/v1/shops/your-shop-slug/webhooks')
request = Net::HTTP::Post.new(uri)
request.basic_auth('your-username', 'your-private-api-key')
request['Content-Type'] = 'application/json'
webhook_data = {
enabled_events: [
"shipments/in_delivery/DELIVERY_ATTEMPTED",
"shipments/delivered"
],
secret: "41013bd9-9072-42cd-9902-66da38361be9",
description: "Shipment Deliveries",
status: "active",
url: "https://example.com/my-webhook-endpoint"
}
request.body = webhook_data.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
webhook = JSON.parse(response.body)
puts webhook
```
If no `enabled_events` is provided, the webhook will listen to `ALL` events (`["*"]`). See [Events](/docs/platform/events/overview) for the full event catalog and how filtering works.
### Configuration fields
| Field | Default | Description |
| ----------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url` | required | Your publicly reachable HTTPS endpoint. Localhost and private-network addresses are rejected, and redirects are not followed — register the final URL of your receiver. |
| `enabled_events` | `["*"]` | The event references to subscribe to. Values outside the [event catalog](/docs/platform/events/overview) are rejected with a `422` validation error. |
| `secret` | generated | The signing secret, 16–64 characters. If you don't provide one, Karla generates it for you. |
| `description` | — | An optional label for the endpoint. |
| `status` | `active` | `active` or `inactive`. Inactive webhooks receive no deliveries. |
| `dedup_enabled` | `true` | Whether shipment events are deduplicated and filtered for staleness before delivery (see below). |
| `stale_event_threshold` | `24` | Hours (`1`–`720`) after which a shipment event counts as stale and is not delivered. Only applies while `dedup_enabled` is `true`. |
### Event deduplication and staleness
By default, Karla filters shipment events before delivering them to your
webhook:
- **One notification per event group.** Several carrier events can map to the
same [event group](/docs/platform/events/shipments); with
`dedup_enabled: true` your endpoint receives at most one notification per
event group per shipment, so you don't need to deduplicate on your side.
- **Stale events are dropped.** A shipment event older than
`stale_event_threshold` hours is not delivered, which keeps late carrier
backfills from triggering outdated notifications.
Set `dedup_enabled: false` if you want the raw firehose instead: every
carrier event is delivered as it arrives, with no deduplication and no
staleness filtering.
:::note
Deduplication applies to shipment events only — claim events are always
delivered.
:::
### Managing webhooks
You can check which webhooks are defined in your shop using the [Search Webhook](https://api.gokarla.io/public/redoc#tag/Webhook/operation/v1.webhooks.search) endpoint.
Webhooks can be updated once they are live, using the [Update Webhook](https://api.gokarla.io/public/redoc#tag/Webhook/operation/v1.webhooks.update) endpoint. You can change `description`, `status`, `url`, `dedup_enabled`, and `stale_event_threshold`; the event selection and the secret are fixed at creation.
```jsx title="PATCH /v1/shops/{slug}/webhooks/{uuid}"
{
"description": "My new description",
"url": "https://example.com/my-new-webhook-endpoint"
}
```
You can delete webhooks with the [Delete Webhook](https://api.gokarla.io/public/redoc#tag/Webhook/operation/v1.webhooks.delete) endpoint.
## Securing your endpoint
You should secure your integration by making sure your handler verifies that all webhook requests are generated by Karla.
We include a `Karla-Signature` header in each signed event that contains a timestamp and a signature
that you should verify. The timestamp has a `t=` prefix, and the signature has a `v1=` prefix.
```text
Karla-Signature:
t=1710864000,
v1=7f3a8b2c1d9e4f6a5b8c7d0e3f2a1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
```
:::note
We provide newlines for clarity, but a real `Karla-Signature` header is on a single line.
:::
Karla generates signatures using a hash-based message authentication code ([HMAC](https://en.wikipedia.org/wiki/HMAC)) with [SHA-256](https://en.wikipedia.org/wiki/SHA-2).
### Verify the signature
1. Extract the timestamp and signatures from the header.
2. Concatenate the timestamp as a string with `.` and the actual JSON payload.
3. Compute an HMAC with the SHA256 hash function. Use the provided signing secret as the key.
4. Compare the signature in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.
### Webhook Verification Sample Code
#### Node.js/TypeScript
```typescript title="Webhook Verification (Node.js)"
import crypto from "crypto";
function verifyKarlaSignature(
payload: string,
signature: string,
secret: string,
): boolean {
const elements = signature.split(",");
const timestamp = elements.find((el) => el.startsWith("t="))?.split("=")[1];
const providedSignature = elements
.find((el) => el.startsWith("v1="))
?.split("=")[1];
if (!timestamp || !providedSignature) {
return false;
}
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(signedPayload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(providedSignature, "hex"),
Buffer.from(expectedSignature, "hex"),
);
}
// Usage
const isValid = verifyKarlaSignature(
JSON.stringify(webhookPayload),
request.headers["karla-signature"],
"your-webhook-secret",
);
```
#### Python
```python title="Webhook Verification (Python)"
import hmac
import hashlib
import time
def verify_karla_signature(payload: str, signature: str, secret: str) -> bool:
elements = signature.split(',')
timestamp = next((el.split('=')[1] for el in elements if el.startswith('t=')), None)
provided_signature = next((el.split('=')[1] for el in elements if el.startswith('v1=')), None)
if not timestamp or not provided_signature:
return False
signed_payload = f"{timestamp}.{payload}"
expected_signature = hmac.new(
secret.encode('utf-8'),
signed_payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(provided_signature, expected_signature)
# Usage
is_valid = verify_karla_signature(
json.dumps(webhook_payload),
request.headers.get('karla-signature'),
'your-webhook-secret'
)
```
## Retry strategy
Karla sends data to your handler via `POST`. In case of an unsuccessful event (non 2xx response), or if your endpoint takes longer than 15s to respond, Karla attempts to deliver your webhooks for up to 15 times with an exponential back off. The event will be lost if all attempts are exhausted.
### Auto-pause on dead endpoints
If your endpoint repeatedly responds with `404` or `410` — the signature of a
deleted or moved receiver — Karla automatically pauses the webhook: its
status is set to `inactive` and deliveries stop. Server errors (`5xx`) never
trigger a pause; they follow the retry strategy above. Any successful (2xx)
delivery resets the failure count, so an endpoint that recovers is not
paused.
:::warning
Keep your endpoint URL alive. If you move or retire a receiver, update the
webhook's `url` (or delete the webhook) instead of letting the old address
return `404`. A paused webhook stays `inactive` until you reactivate it in
the [Karla Portal](https://portal.gokarla.io) or set its `status` back to
`active` via the [Update Webhook](https://api.gokarla.io/public/redoc#tag/Webhook/operation/v1.webhooks.update) endpoint.
:::
## Specification
### Header
```yaml
Host: api.gokarla.io
Content-Length: 12345
User-Agent: KarlaWebhookClient/1.0
Karla-Signature: t=1710864000,v1=7f3a8b2c1d9e4f6a5b8c7d0e3f2a1b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
Content-Type: application/json
```
### Body
Body follows the format described in the [Events](/docs/platform/events/overview) reference.
## IP Whitelisting
If your service has a Firewall restricting public IPs, please add `34.77.48.225` to the allow list.
:::note
Sending traffic to your systems via a static IP is a premium service that has to be enabled in advance.
:::
---
## Email flows
Source: https://gokarla.io/docs/guides/notify/email-flows
# Email flows
Email flows are the emails Karla sends to your customers on your behalf —
order updates, delivery issues, resolve confirmations — built from templates
you own and manage. In the [Karla Portal](https://portal.gokarla.io), go to
**Notify → Email templates** to open the **Email flows** page.
:::note Email flows, integrations, or custom triggers?
Karla Notify has a few distinct pieces. **Email flows** (this page) are the
content of emails Karla itself sends. The
[Notify integrations](/docs/guides/notify/integrations/klaviyo) forward
shipment events to an external email tool (Klaviyo, Brevo, …) that sends its
own emails. [Custom triggers](/docs/guides/notify/custom-triggers) are
time-based signals delivered to Klaviyo as metrics — they don't send emails
themselves.
:::
## Availability and roles
Sending emails through Karla is a premium add-on. Until it's enabled for your
shop, the page shows a **Karla email sending** banner with a **Premium**
badge — you can browse the catalog and preview templates, but not create or
send anything. Use the **Contact us** button to get it enabled.
What you can do on the page depends on your portal role:
| Role | What you can do |
| ------ | -------------------------------------------------------------- |
| viewer | Browse flows, the templates catalog, and previews |
| editor | Create, edit, activate, and test-send flows |
| admin | Everything above, plus delete flows and change sender settings |
## The three tabs
| Tab | What it's for |
| ---------------------- | ----------------------------------------------------------------- |
| **Active email flows** | The flows your shop owns — activate, test, edit, and delete them |
| **Templates catalog** | Ready-made templates to clone into your shop |
| **Settings** | Sender settings, and the custom sending domain on enterprise tier |
## Start from the catalog
The **Templates catalog** tab lists ready-made templates grouped into
**Order update emails** and **Resolve emails**, so you never start from a
blank page.
- **Preview** opens the template in a side panel; templates that exist in
several languages show one tab per language.
- **Use template** clones the template into your shop's flows — a toast
confirms it was added. Multi-language templates show **Choose language**
instead: pick the language in the preview and confirm with
**Use template in EN** (or the language you chose).
:::note The Automatic badge
Some catalog cards carry an **Automatic** badge. It's a category hint derived
from the template's tags — it doesn't schedule or send anything by itself. A
flow only goes out when something sends it, such as the **Send Karla email**
action in [Shopify Flow](/docs/platform/email-templates).
:::
## Edit your flow
New flows open in the **block builder**; templates cloned from the catalog
open in the raw HTML editor, since they ship as full HTML documents. The
block builder shows a live preview next to these fields:
| Field | What it does |
| --------------------------- | --------------------------------------------------------------------------------------------- |
| **Email title** | The flow's name in your list |
| **Tags** | Freeform labels for organizing and filtering your flows |
| **Enable email automation** | Whether the flow is active — same as the **Active** switch in the list |
| **Language** | The flow's language. Multi-language flows aren't supported yet, and it can't be changed later |
| **Subject** | The email subject line |
| **Email preview** | The preheader text inboxes show next to the subject |
| **Upload Email hero** | The hero image at the top of the email |
The body is assembled from **Text**, **Image**, and **Spacer** blocks that
you can reorder and remove. Text blocks offer White, Light gray, and Gray
backgrounds; spacers range from 8 to 48 px. The footer's logo, colour, and
content are configurable as well. Save with **Save and create** for a new
flow, or **Save changes** when editing.
## Personalize with variables
Write variables with double braces — `{{ variable }}` — and Karla fills in
the value per customer and shipment at send time. The editor lists every
available variable as a clickable chip, grouped into **Shipment variables**,
**Resolve variables**, **Customer variables**, and **Other variables**; click
a chip to insert it into the focused field.
- Substitution is plain token replacement — no conditionals, loops, or
filters.
- Unknown variables — and known variables the send has no value for — render
as an **empty string**, so a stray token never leaks into a customer email.
- Values are HTML-escaped automatically.
- Append `_urlencoded` to any variable name (like
`{{ order_number_urlencoded }}`) to insert its URL-encoded value for use
inside links.
The full variable list, and which events populate which value, lives in the
[email templates reference](/docs/platform/email-templates).
## Activate and test
Back on **Active email flows**, each flow has an **Active** switch. Only
active flows can be sent — for example by the **Send Karla email** action in
[Shopify Flow](/docs/platform/email-templates) — and only active flows can
receive a test email.
To sanity-check a flow, click its **Send test email** action (for inactive
flows the button is disabled with the hint "Activate the template to send a
test email"). Enter a **Recipient** — the field is prefilled with your own
email address — and click **Send test**. The test email fills all variables
with sample values, and a toast confirms it was queued.
## Manage your flows
The **Active email flows** table shows each flow's **Name**, **Language**,
**Tags**, and **Active** state, with a search box to filter by name.
**Create new flow** starts a fresh flow in the block builder. Deleting a flow
is admin-only and permanent — the confirmation dialog warns that the template
will be permanently deleted.
## Sender settings
The **Settings** tab shows whether Karla email sending is **Enabled** for
your shop, and lets shop admins adjust how sent emails present themselves:
| Setting | Default | What it does |
| ----------------------- | --------------------- | ------------------------------------------------- |
| **Replies sent to** | `no-reply@gokarla.io` | The reply-to address, e.g. `support@yourshop.com` |
| **Sender display name** | Your shop's name | The sender name customers see in their inbox |
Click **Save sender settings** to apply the changes (admin only).
On the enterprise email tier you can go further and send from your own
domain — see
[Send from your own domain](/docs/guides/notify/sender-domain).
---
## Send from your own domain
Source: https://gokarla.io/docs/guides/notify/sender-domain
# Send from your own domain
By default, Karla [email flows](/docs/guides/notify/email-flows) are sent
from the Karla default sender. On the **enterprise** email tier you can send
from your own domain instead, so customers see an address like
`shipping@yourshop.com` in their inbox and your emails are authenticated
under your name.
You'll find the **Custom sending domain** card in the
[Karla Portal](https://portal.gokarla.io) under
**Notify → Email templates → Settings**. On other tiers the card shows an
**Enterprise** badge and a **Contact us** button.
:::note What this affects
The custom sending domain only changes the sender of emails Karla itself
sends — your [email flows](/docs/guides/notify/email-flows). Emails sent by
an integrated tool like Klaviyo or Brevo are configured in that tool, not
here.
:::
Before you start, make sure:
- You have the shop **admin** role in the portal — registering, activating,
and deactivating the sender are admin-only.
- You can edit your domain's DNS records at your domain provider.
## 1. Register your domain
Enter your domain in **Your domain** — the domain your customers know,
without `@` or `https://`, for example `yourshop.com` — and click
**Register domain**. Karla confirms with "Domain registered. Add the DNS
records below." and generates the DNS records for you to publish.
## 2. Publish the DNS records
Each record is listed with its purpose, type, name/host, and value, ready to
copy into your DNS provider:
| Record | Type | Requirement | What it does |
| -------------------------- | ----- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **DKIM authentication** | CNAME | Required | Signs your emails so inbox providers can verify them — records like `._domainkey.yourshop.com` → `.dkim.amazonses.com` |
| **Bounce handling (MX)** | MX | Recommended | Routes bounce reports back to Karla — `mail.yourshop.com` → `feedback-smtp..amazonses.com`, priority 10 |
| **Bounce handling (SPF)** | TXT | Recommended | Authorizes the bounce subdomain — a TXT record on `mail.yourshop.com` with `v=spf1 include:amazonses.com ~all` |
| **Ownership verification** | TXT | Required | Proves you control the domain — a TXT record on `_karla-sender.yourshop.com` with a `karla-verification=…` value unique to your shop |
Keep in mind:
- Activation only needs the **Required** records — the recommended ones
improve deliverability once verified.
- No changes to your domain's existing SPF record are needed — the SPF
record above lives on the `mail.` subdomain.
- Using Cloudflare? Set these records to **DNS only** (grey cloud) so
verification can see them.
- Keep the records published for as long as your custom sender is active.
## 3. Check the verification status
DNS changes can take up to a few hours to propagate. Click **Check status**
to refresh — Karla reads the state live on every check. Three badges track
progress: **DKIM**, **Bounce handling**, and **Ownership**, each shown as
**Pending**, **Verified**, or **Failed**.
Registered the wrong domain? **Use a different domain** resets the form so
you can start over.
## 4. Activate your sender address
Once **DKIM** and **Ownership** are verified, choose the address your emails
are sent from: type the part before the `@` into **Send emails from** (for
example `shipping`) and click **Activate sender**. The portal confirms with
"Custom sender activated." — from now on, your email flows are sent from that
address.
## While your sender is active
The card shows "Emails are sent from `shipping@yourshop.com`" with an
**Active** badge and the verification badges. **View DNS records** reopens
the record list — useful when moving DNS providers, since the records must
stay published while the sender is active.
To switch back to the Karla default sender, click **Deactivate custom
sender** and confirm. Karla confirms the deactivation and your emails use
the Karla default sender again.
---
## Custom triggers
Source: https://gokarla.io/docs/guides/notify/custom-triggers
# Custom triggers
Custom triggers watch your shipments over time and raise a hand when
something takes too long — an order created but not fulfilled for six days, a
parcel sitting in transit for a week. When a shipment has been stuck in a
state you chose for longer than your threshold, the trigger fires an event
into Klaviyo, where you build the follow-up flow.
In the [Karla Portal](https://portal.gokarla.io), go to
**Notify → Custom triggers**.
:::important Custom triggers are not email flows
[Email flows](/docs/guides/notify/email-flows) are the content of emails
Karla itself sends. **Custom triggers** don't send any email — each one
delivers a metric into Klaviyo when its time condition is met, and your
Klaviyo flow decides what happens next. Custom triggers are currently only
available for Klaviyo; native Notify support is coming soon.
:::
## Prerequisites
- A connected [Klaviyo integration](/docs/guides/notify/integrations/klaviyo).
Without one, the page shows a **Connect Klaviyo first** prompt that links
you to the integration settings.
- The **editor** role (or above) in the portal to create or delete triggers.
## How a trigger works
- A trigger watches shipments in the events or phases you select. Karla
periodically evaluates your triggers against your recent shipments.
- When a shipment has been stuck longer than the time threshold, Karla sends
an event to Klaviyo under the metric
`karla__internal_trigger`.
- Threshold hours **skip Sundays and German public holidays** — a 144-hour
threshold reaches further back than six calendar days when a Sunday or
holiday falls in between.
- Only shipments **created in the last 30 days** are checked.
- A trigger fires **at most once per order** — once it has fired, it stays
quiet for that order's shipments.
## Create a trigger
Click **Create new trigger**. The form reminds you that custom triggers
currently work with Klaviyo-powered stores, then asks for:
### Trigger name
Names both the trigger and its Klaviyo metric. The recommended format is
`order_status_condition_timeframe`, for example
`order_created_not_fulfilled_6_days`. Spaces and special characters convert
to underscores automatically, and the final name is lowercase. That example
produces the Klaviyo metric
`karla_order_created_not_fulfilled_6_days_internal_trigger`.
### Events
Pick individual events, or select a whole phase — phases automatically
include new carrier events added to them later. The picker groups events
under the shipment phases: Order created, Order processed, Order cancelled,
Collect, In transit, In delivery, Delivered, Delivery failed, Return created,
Return transit, Return received, Return failed, and Returned. See the
[shipment events reference](/docs/platform/events/shipments) for what each
phase covers.
### Time threshold type
When should the timer start?
| Option | The timer counts from |
| --------------------------------- | ----------------------------------- |
| **After latest update** (default) | The shipment's most recent event |
| **From creation** | The moment the shipment was created |
### Set time threshold (hours)
How long the shipment must be stuck before the trigger fires. Whole hours
only, from 1 to 600 (25 days); the default is 144 (6 days). For thresholds
of 480 hours or more the portal shows a heads-up: since only the last 30
days of shipments are checked, very high thresholds leave little room to
match.
As you fill in the form, a live preview spells out exactly what will fire —
for example: "Shipments stuck in any In transit state since before Tue, Aug 4
at 09:00 will fire this trigger — that's 144 hours back, skipping Sundays and
German public holidays."
Click **Create Trigger** to save. The trigger is live immediately.
## Find the metric in Klaviyo
As soon as you create a trigger, Karla seeds its metric with a single test
event so it shows up in Klaviyo right away — Klaviyo only offers a metric to
flow builders after receiving at least one event of it, so you don't have to
wait for a real shipment to match.
In Klaviyo, create a flow triggered by the metric
`karla__internal_trigger` and build your follow-up — an apology
email, a support ticket, an internal alert. See
[Building Klaviyo flows](/docs/guides/notify/integrations/klaviyo#building-klaviyo-flows)
for the general pattern.
## Manage your triggers
The **Your triggers** list shows every trigger, with a search box to filter:
| Column | What it shows |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Trigger name** | The slugified name, as it appears in the Klaviyo metric |
| **Watching** | The selected events or phases ("3 events", "2 phases", "Any event"), any excluded events, and a **Return** chip for return shipments |
| **Threshold** | The time threshold (e.g. "6 days") and its type |
Click a trigger to open its details:
- The conditions — event type, events or phases, exceptions, and threshold
type — are read-only.
- Only **Set time threshold (hours)** can be edited and saved.
- To change anything else, open **More actions → Duplicate trigger**, which
prefills the create form with the trigger's conditions — adjust them, save
the new trigger, then delete the old one.
- **Delete** removes the trigger permanently; this cannot be undone. There is
no enable/disable switch — a trigger fires as long as it exists.
---
## Klaviyo
Source: https://gokarla.io/docs/guides/notify/integrations/klaviyo
# Klaviyo
:::info
The Klaviyo x Karla integration allows you to use Karla’s shipping events as triggers for post-purchase flows and inform your customers about shipping updates via email.
:::
## Quick connect (recommended)
The fastest way to connect Karla to Klaviyo is **Quick connect** — a secure, one-click OAuth connection. There are no API keys to create, copy, or manage.
In the [Karla portal](https://portal.gokarla.io), go to **Settings → Integrations** and click **Configure** on the Klaviyo card.
In the **Quick connect** card, click **Connect Klaviyo** and approve Karla on the Klaviyo consent screen. No API keys to copy.
The **Connection** card shows a green **Connected** badge and the status **Connected and working**.
Karla seeds your shipment metrics on connect. In Klaviyo, open **Analytics → Metrics** and look for `shipment_out_for_delivery`, `shipment_delivered`, and more.
Once connected, skip ahead to [Building Klaviyo Flows](#building-klaviyo-flows) to create your first flow.
:::note
You can disconnect at any time from the same Klaviyo integration page — click **Disconnect** to remove Karla's stored Klaviyo token. You can reconnect whenever you like.
:::
## Connect with an API key
Prefer to connect manually, or don't have Quick connect available yet? You can provide a Klaviyo **Private API key** instead. This only takes 2 minutes.
### 1. Open Klaviyo & navigate to Settings

### 2. Select API key and click on Create Private API Key

### 3. Name it "Karla Integration" and select the scope and confirm with Create
You should select the following scopes (`Read/Write Access`) that allows us to:
- **Events**: send events to your Klaviyo account
- **Metrics**: integrate your metrics with Karla
- **Profiles**: access profile data
- **List**: read lists to enable segmented campaigns
- **Segments**: read segments to enable segmented campaigns
- **Flows**: read flows to enable flow-based insights

### 4. Copy the Private API key

### 5. Set the API key in the Karla portal
In our [portal](https://portal.gokarla.io/), navigate to `Settings` > `Integrations` and select `Klaviyo`.

Paste the API key into the `Private API Key` field and click on `Save`.

Once the key has been saved successfully, you can toggle the integration settings.

## Building Klaviyo Flows
:::info
To relieve you of the work involved in setting up the Klaviyo flows, we transfer our flows including email templates to your Klaviyo account.
If you connected with **Quick connect**, the OAuth grant already covers this — Karla holds the flow permissions it needs and no extra access is required. If you connected with a **Private API key**, that key only grants read access to flows, so we ask for (temporary) admin access ([infrastructure@gokarla.io](mailto:infrastructure@gokarla.io)) to your Klaviyo account for the transfer.
As soon as all flows have been transferred to your account, you can customize the email templates as you wish (e.g. branding, wording, etc.).
:::
To cover the most important delivery journey events, we recommend first of all creating the flows for following **event groups**:
1. `shipment_in_transit`
2. `shipment_carrier_delay`
3. `shipment_damaged`
4. `shipment_out_for_delivery`
5. `shipment_delivered`
6. `shipment_delivered_to_neighbour`
7. `shipment_delivered_to_letterbox`
8. `shipment_delivered_to_parcel_shop`
9. `shipment_not_picked_up_then_returned`
10. `shipment_failed_returned`
By creating these 10 flows you will be able to cover standard events happening for every order (`shipment_in_transit`, `shipment_out_for_delivery` ), all delivered cases (`shipment_delivered`, `shipment_delivered_to_neighbour`, `shipment_delivered_to_letterbox`, `shipment_delivered_to_parcel_shop`) and the events that hopefully do not happen too often, but where it is most important to be proactive with your customers (`shipment_carrier_delay`, `shipment_damaged`, `shipment_not_picked_up_then_returned`, `shipment_failed_returned` ).
:::info Event Groups vs Webhook Refs
**Klaviyo** uses **event groups** (like `shipment_delivered`) while **webhooks** use **ref patterns** (like `shipments/delivered/SUCCESSFULLY_DELIVERED`). Event groups are business-friendly names that group multiple specific events for easier flow management.
For complete documentation, see: **[Events Reference →](/docs/platform/events/overview)**
:::
### Pickup Reminder Flow
## Inserting the tracking page link
To include the tracking page link in your Klaviyo emails you should use a dynamic link with `order_number` and `zip_code` variables, so that your customers always receive their personalised link:
For emails triggered through Klaviyo:
### Karla events
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ event.order_number|default:'' }}&zipCode={{ event.zip_code|default:'' }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ event.order_number|default:'' }}&zipCode={{ event.zip_code|default:'' }}&ref=karla
```
### Shipping Confirmation
Triggered by Shopify's `Fulfilled_Order` Event.
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ event.extra.order_number|default:'' }}&zipCode={{ event.extra.shipping_address.zip|default:'' }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ event.order_number|default:'' }}&zipCode={{ event.zip_code|default:'' }}&ref=karla
```
:::tip
A `slug` is your unique identifier that represents your shop within the Karla system. This is used to properly route tracking information and ensure that shipment data is associated with the correct merchant account.
:::
## Testing the flows
Once you've set up the flows and the respective emails it is important you make sure that the integration is working as expected.
In the Email Template Editor go to Preview & Test

There make sure that in the profiles you see the information from the profiles from your shop and not from Karla's test events. These should be infos like customer name, order number, shipping address etc.
:::warning
You will see this information only after you have integrated your Shopify/Shopware Shop and Klaviyo with Karla. [More on shop integrations](/docs/guides/shops/overview)
:::

If you want to see how your customers will receive the emails, you can send a test email to your email-address.

### Putting the flows live
After you have tested your flows, you can put them live upon the agreed go-live date.
:::warning
Make sure you have requested the transactional status for your Karla flows (more on the transactional status here) and have disabled the Smart Sending feature, so that all of your customers receive there shipping updates.
:::

## Event Groups
Karla provides the following **event groups** to your Klaviyo instance for building flows. These are business-friendly groupings that make it easier to create targeted campaigns without dealing with individual event names.
:::info Event Groups vs Webhook Patterns
Event groups are specifically designed for **Klaviyo integration** and are different from webhook ref patterns:
- **Event Groups**: Business-friendly names (e.g., `shipment_delivered`)
- **Webhook Refs**: Technical identifiers (e.g., `shipments/delivered/SUCCESSFULLY_DELIVERED`)
For complete documentation of all events, ref patterns, and event groups, see: **[Events Reference →](/docs/platform/events/overview)**
:::
### Claims
For any processed claim (e.g. damaged package, package not found...).
See [Claims](https://api.gokarla.io/public/redoc#tag/Claim).
- `karla_claim_created`
- `karla_claim_updated`
### Shipments
For any processed shipment update:
| Event Group | Description | Use Case |
| --------------------------------------------------- | ------------------------------ | ------------------------------ |
| `shipment_pre_transit` | Package prepared for shipping | Confirmation emails |
| `shipment_in_transit` | Package moving through network | Journey updates |
| `shipment_carrier_delay` | Carrier-reported delays | Proactive communication |
| `shipment_damaged` | Package damage reported | Customer service outreach |
| `shipment_out_for_delivery` | Package out for delivery | Delivery notifications |
| `shipment_delivered` | Successful delivery | Delivery confirmations |
| `shipment_delivered_all_events` | All delivery variations | Comprehensive delivery flows |
| `shipment_delivered_to_letterbox` | Delivered to letterbox | Specific delivery method |
| `shipment_delivered_to_neighbour` | Delivered to neighbor | Neighbor delivery notification |
| `shipment_delivered_to_parcel_locker` | Delivered to parcel locker | Pickup instructions |
| `shipment_delivered_to_parcel_shop` | Delivered to pickup point | Pickup notifications |
| `shipment_delivery_failed` | Delivery attempt failed | Retry communications |
| `shipment_delivery_failed_address_issue` | Address problems | Address correction requests |
| `shipment_delivery_failed_forwarded_to_parcel_shop` | Forwarded to pickup | Alternative pickup location |
| `shipment_delivery_second_attempt` | Reattempting delivery | Second attempt notifications |
| `shipment_not_picked_up_then_returned` | Not picked up, returned | Return notifications |
| `shipment_refused_then_returned` | Customer refused package | Return processing |
| `shipment_failed_returned` | Package returned to sender | Return confirmations |
| `shipment_picked_up` | Successfully picked up | Pickup confirmations |
### Recommended Flow Priority
**High Priority** (Essential flows):
1. `shipment_in_transit` - Keep customers informed
2. `shipment_out_for_delivery` - Delivery readiness
3. `shipment_delivered` - Delivery confirmation
4. `shipment_carrier_delay` - Proactive communication
**Medium Priority** (Enhanced experience): 5. `shipment_delivered_to_parcel_shop` - Pickup instructions 6. `shipment_delivery_failed` - Retry coordination 7. `shipment_damaged` - Customer service escalation
**Lower Priority** (Edge cases): 8. `shipment_not_picked_up_then_returned` - Return processing 9. `shipment_failed_returned` - Return confirmation 10. `claim_created` - Claims management
## Need help?
Questions about connecting Karla and Klaviyo? Email us at [hello@gokarla.io](mailto:hello@gokarla.io) and we'll help you get your first flow live.
## Related articles
- [WhatsApp](/docs/guides/notify/integrations/whatsapp) — forward these same Klaviyo triggers to WhatsApp.
---
## Shopware
Source: https://gokarla.io/docs/guides/notify/integrations/shopware
# Shopware
The Shopware integration allows Karla to provide notifications about shipments and claims involved in your orders natively to your admin instance.
## Flows
You can configure your own flows on the data received by our systems with the [Flow Builder](https://www.shopware.com/en/products/ecommerce-automation/flow-builder/).
### Triggers
Karla provides [Event Groups](/docs/platform/events/overview#key-concepts) to your shop, which will be available in the Flow Builder via [Triggers](https://docs.shopware.com/en/shopware-6-en/settings/Flow-Builder#trigger), if the [Webhook Receiver setting is activated](/docs/guides/shops/shopware#webhook-receiver-incoming-events).

### Actions
You can create [Actions](https://docs.shopware.com/en/shopware-6-en/settings/Flow-Builder#action) reacting on those triggers.

A common action is to send an email based on a specific email template.

## Email Templates
You can define your own [Email templates](https://docs.shopware.com/en/shopware-6-en/settings/email-templates?category=shopware-6-en/settings/shop) so they can be used within a Flow action.
You can use any of the [Shopware variables in the mail text](https://docs.shopware.com/en/shopware-6-en/settings/email-templates?category=shopware-6-en/settings/shop#variables-in-the-mail-text).

Karla exposes new variables on its own, received by the trigger, that you can render within the email template.

### Karla variables
Any variable exposed by karla is accessible via the `karla` object, for instance `{{ karla.tracking_number }}`.
The variables exposed in this object are same as documented in [Event-specific Data](/docs/platform/events/overview#payload-envelope), (`karla` is the object instead of `event_data` in this case).
---
## HubSpot
Source: https://gokarla.io/docs/guides/notify/integrations/hubspot
# HubSpot
:::info
The HubSpot integration allows Karla to provide your HubSpot account with triggers of any sort, like shipment notifications or claims.
:::
## Steps
### 1. Open HubSpot & navigate to Settings
Navigate to your HubSpot instance and click on the `Settings` gear icon in the main navigation bar.

### 2. Create a Private App
In the left sidebar, navigate to `Integrations` → `Legacy Apps`.
Click on `Create`

Click on `Private`

Fill the Basic Info

Add the required scopes

- **Contact Management**: read contact profiles to match customers
- **Event Tracking**: send custom events to your HubSpot account
These permissions are mandatory to have the minimum notification functionality working:
- `analytics.behavioral_events.send`: allows Karla to send custom events via API
- `crm.objects.contacts.read`: will read contact emails to match delivery events
- `behavioral_events.event_definitions.read_write`: will create `karla_*` custom events
:::note
The exact naming and location of scopes may vary slightly based on your HubSpot version. Look for scopes related to:
- Reading contacts/CRM data
- Sending behavioral or custom events
:::
Skip the `Webhooks` section and click on `Create app` at the top.

Once you click on `Continue creating`, go to the `Auth` tab, `Show Token` and `Copy` the Access Token.

### 3. Set up the Private App Access Token in Karla
After selecting the scopes, click on `Create app` and confirm. HubSpot will generate a **Private App Access Token**.
Copy the access token from the generated credentials.
In our [portal](https://portal.gokarla.io/), navigate to `Settings` > `Integrations`, and select `HubSpot`.

Paste the `Private App Access Token` and click on `Save`.

Once the key has been saved successfully, you can toggle the integration settings.
:::warning Security Note
- Treat this token like a password
- Only share it through secure channels
- You can regenerate the token anytime if needed
:::
## Building HubSpot Workflows
Our HubSpot integration will automatically create custom events prefixed with `karla_` for all delivery journey events.
From there, you can create automation workflows relying on these events to configure your own email flows.
### Workflow Priority Recommendations
To cover the most important delivery journey events, we recommend first creating workflows for the following **event groups**:
1. `karla_shipment_in_transit`
2. `karla_shipment_carrier_delay`
3. `karla_shipment_damaged`
4. `karla_shipment_out_for_delivery`
5. `karla_shipment_delivered_all_events`
6. `karla_shipment_not_picked_up_then_returned`
7. `karla_shipment_failed_returned`
By creating these 7 workflows you will be able to cover standard events happening for every order (`karla_shipment_in_transit`, `karla_shipment_out_for_delivery`), all delivered cases (`karla_shipment_delivered_all_events`) and the events that hopefully do not happen too often, but where it is most important to be proactive with your customers (`karla_shipment_carrier_delay`, `karla_shipment_damaged`, `karla_shipment_not_picked_up_then_returned`, `karla_shipment_failed_returned`).
:::info Event Groups vs Webhook Refs
**HubSpot** uses namespaced **event groups** (like `karla_shipment_delivered`) while **webhooks** use **ref patterns** (like `shipments/delivered/SUCCESSFULLY_DELIVERED`). Event groups are business-friendly names that group multiple specific events for easier automation management.
For complete documentation, see: **[Events Reference →](/docs/platform/events/overview)**
:::
### Pickup Reminder Workflow
Create an automated workflow that triggers pickup reminders for packages delivered to parcel shops or lockers that haven't been collected within a specified timeframe.
## Inserting the tracking page link
To include the tracking page link in your HubSpot transactional emails you should use personalization tokens with `order_number` and `zip_code` properties, so that your customers always receive their personalized link:
For emails triggered through HubSpot:
### Karla events
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ contact.order_number }}&zipCode={{ contact.zip_code }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ contact.order_number }}&zipCode={{ contact.zip_code }}&ref=karla
```
### Shipping Confirmation
Triggered by external events from your shop system.
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ contact.order_number }}&zipCode={{ contact.shipping_zip }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ contact.order_number }}&zipCode={{ contact.zip_code }}&ref=karla
```
:::tip
A `slug` is your unique identifier that represents your shop within the Karla system. This is used to properly route tracking information and ensure that shipment data is associated with the correct merchant account.
:::
## Testing the workflows
Once you've set up the workflows and the respective emails it is important you make sure that the integration is working as expected.
In the Email Template Editor go to Preview & Test functionality.
There make sure that in the contact data you see the information from the profiles from your shop and not from Karla's test events. These should be infos like customer name, order number, shipping address etc.
:::warning
You will see this information only after you have integrated your shop and HubSpot with Karla. [More on shop integrations](/docs/guides/shops/overview)
:::
If you want to see how your customers will receive the emails, you can send a test email to your email address.
### Putting the workflows live
After you have tested your workflows, you can put them live upon the agreed go-live date.
:::warning
Make sure you have configured the proper sending settings and have disabled any frequency caps for transactional emails, so that all of your customers receive their shipping updates.
:::
## Event Groups
Karla provides the following **event groups** to your HubSpot instance for building workflows. These are business-friendly groupings that make it easier to create targeted campaigns without dealing with individual event names.
:::info Event Groups vs Webhook Patterns
Event groups are specifically designed for **HubSpot integration** and are different from webhook ref patterns:
- **Event Groups**: Business-friendly names, prefixed by `karla_` (e.g., `karla_shipment_delivered`)
- **Webhook Refs**: Technical identifiers (e.g., `shipments/delivered/SUCCESSFULLY_DELIVERED`)
For complete documentation of all events, ref patterns, and event groups, see: **[Events Reference →](/docs/platform/events/overview)**
:::
### Claims
For any processed claim (e.g. damaged package, package not found...).
See [Claims](https://api.gokarla.io/public/redoc#tag/Claim).
- `karla_created`
- `karla_updated`
:::note
Claim events do **not** carry the `shipment_`-style group name that shipment
events do — they arrive in HubSpot as `karla_created` and `karla_updated`.
Build your claim workflows on those two names.
:::
### Shipments
For any processed shipment update:
| Event Group | Description | Use Case |
| --------------------------------------------------------- | ------------------------------ | ------------------------------ |
| `karla_shipment_pre_transit` | Package prepared for shipping | Confirmation emails |
| `karla_shipment_in_transit` | Package moving through network | Journey updates |
| `karla_shipment_carrier_delay` | Carrier-reported delays | Proactive communication |
| `karla_shipment_damaged` | Package damage reported | Customer service outreach |
| `karla_shipment_out_for_delivery` | Package out for delivery | Delivery notifications |
| `karla_shipment_delivered` | Successful delivery | Delivery confirmations |
| `karla_shipment_delivered_all_events` | All delivery variations | Comprehensive delivery flows |
| `karla_shipment_delivered_to_letterbox` | Delivered to letterbox | Specific delivery method |
| `karla_shipment_delivered_to_neighbour` | Delivered to neighbor | Neighbor delivery notification |
| `karla_shipment_delivered_to_parcel_locker` | Delivered to parcel locker | Pickup instructions |
| `karla_shipment_delivered_to_parcel_shop` | Delivered to pickup point | Pickup notifications |
| `karla_shipment_delivery_failed` | Delivery attempt failed | Retry communications |
| `karla_shipment_delivery_failed_address_issue` | Address problems | Address correction requests |
| `karla_shipment_delivery_failed_forwarded_to_parcel_shop` | Forwarded to pickup | Alternative pickup location |
| `karla_shipment_delivery_second_attempt` | Reattempting delivery | Second attempt notifications |
| `karla_shipment_not_picked_up_then_returned` | Not picked up, returned | Return notifications |
| `karla_shipment_refused_then_returned` | Customer refused package | Return processing |
| `karla_shipment_failed_returned` | Package returned to sender | Return confirmations |
| `karla_shipment_picked_up` | Successfully picked up | Pickup confirmations |
| `karla_shipment_delayed_due_to_customer_request` | Customer requested delay | Confirmation of delay request |
### Priority Guide for Workflows
**High Priority** (Essential workflows):
1. `karla_shipment_in_transit` - Keep customers informed
2. `karla_shipment_out_for_delivery` - Delivery readiness
3. `karla_shipment_delivered` - Delivery confirmation
4. `karla_shipment_carrier_delay` - Proactive communication
5. `karla_shipment_delivered_all_events` - Any delivery event
**Medium Priority** (Enhanced experience):
1. `karla_shipment_delivered_to_parcel_shop` - Pickup instructions
2. `karla_shipment_delivery_failed` - Retry coordination
3. `karla_shipment_damaged` - Customer service escalation
**Lower Priority** (Edge cases):
1. `karla_shipment_not_picked_up_then_returned` - Return processing
2. `karla_shipment_failed_returned` - Return confirmation
3. `karla_created` - Claims management
## Common Use Cases
### Post-Delivery Review Request
**Event Group**: `karla_shipment_delivered`
**Timing**: 2-3 days after delivery
**Content**: Thank you message + review request
### Pickup Reminder
**Event Group**: `karla_shipment_delivered_to_parcel_shop`
**Timing**: Immediate + daily reminders
**Content**: Pickup location, hours, deadline
### Delivery Issue Resolution
**Event Group**: `karla_shipment_delivery_failed`
**Timing**: Immediate
**Content**: Failed reason, next steps, support link
### Proactive Delay Communication
**Event Group**: `karla_shipment_carrier_delay`
**Timing**: As soon as delay detected
**Content**: New ETA, apology, compensation if applicable
## Best Practices
### 1. Email Content Guidelines
- **Be Specific**: Reference the exact delivery status
- **Include CTAs**: Add tracking links and next steps
- **Personalize**: Use customer and order data available from the event
- **Mobile-Optimize**: Most tracking emails are read on mobile
### 2. Testing Recommendations
1. Test each event group workflow separately
2. Verify personalization tokens populate correctly
3. Check email rendering across devices
4. Monitor delivery rates and engagement
## Troubleshooting
### Events Not Triggering Emails
1. Verify event group name matches exactly (case-sensitive)
2. Check integration credentials are active
3. Confirm workflow is published in HubSpot
4. Test with Karla test events
### Missing Data in Emails
1. Ensure all personalization tokens match the event properties
2. Check token syntax (`{{ contact.field_name }}`)
3. Verify contact property mapping
### Email Delivery Issues
1. Check HubSpot sending logs
2. Verify customer email addresses
3. Review spam folder placement
4. Check domain authentication (SPF/DKIM)
### Cannot Find Private Apps Option
- Verify you have **Super Admin** permissions
- Check if your HubSpot subscription tier supports Private Apps
- Try looking under Settings → Integrations → API Key (for legacy setups)
- Contact HubSpot support to enable Private Apps for your account
### Token Not Working
- Ensure you copied the complete token
- Verify the selected scopes match the requirements above
- Check that you're using your production account, not a test account
- Confirm the Private App is active (not deactivated)
## Security Best Practices
- **Rotate tokens periodically** - You can regenerate the token in HubSpot without breaking the integration (just update it in Karla)
- **Monitor app activity** - HubSpot provides logs of API calls made by your Private App
- **Limit scopes** - Only grant the minimum required permissions listed above
- **Use secure channels** - Never share tokens via email or public channels
## Support
- **Karla Integration Support**: support@gokarla.io
- **HubSpot Technical Support**: Refer to your HubSpot account manager
- **Technical Documentation**: [Karla Events](/docs/platform/events/overview)
## Next Steps
1. Identify which event groups align with your communication strategy
2. Create workflows for your priority events
3. Design and test email templates
4. Monitor performance and optimize
---
## Brevo
Source: https://gokarla.io/docs/guides/notify/integrations/brevo
# Brevo
:::info
The Brevo integration allows Karla to provide your Brevo account with triggers of any sort, like shipment notifications or claims.
:::
## Steps
### 1. Open Brevo & navigate to SMTP & API
Navigate to your Brevo instance and click on `SMTP & API` in the main navigation.
### 2. Create API Key
In the API Keys section, click on `Generate a new API key` to create new API access.
Name your API key "Karla Integration" and select the necessary permissions.
See [Create and manage your Brevo API Keys](https://help.brevo.com/hc/en-us/articles/209467485-Create-and-manage-your-API-keys).
### 3. Copy the API Key
Copy the generated API key from Brevo.
In our [portal](https://portal.gokarla.io/), navigate to `Settings` > `Integrations`, look for `Brevo`.

Paste the API key into the `API Key` field and click on `Save`.
:::note
Please contact our account manager if access to settings is not enabled for you in the portal. We can enable the setting for you.
:::
## Building Brevo Automations
Our Brevo integration will automatically create custom events prefixed with `karla_` for all delivery journey events.
From there, you can create automation workflows relying on these events to configure your own email flows.
### Recommended Flow Priority
To cover the most important delivery journey events, we recommend first creating automations for the following **event groups**:
1. `karla_shipment_in_transit`
2. `karla_shipment_carrier_delay`
3. `karla_shipment_damaged`
4. `karla_shipment_out_for_delivery`
5. `karla_shipment_delivered_all_events`
6. `karla_shipment_not_picked_up_then_returned`
7. `karla_shipment_failed_returned`
By creating these 7 automations you will be able to cover standard events happening for every order (`karla_shipment_in_transit`, `karla_shipment_out_for_delivery`), all delivered cases (`karla_shipment_delivered_all_events`) and the events that hopefully do not happen too often, but where it is most important to be proactive with your customers (`karla_shipment_carrier_delay`, `karla_shipment_damaged`, `karla_shipment_not_picked_up_then_returned`, `karla_shipment_failed_returned`).
:::info Event Groups vs Webhook Refs
**Brevo** uses namespaced **event groups** (like `karla_shipment_delivered`) while **webhooks** use **ref patterns** (like `shipments/delivered/SUCCESSFULLY_DELIVERED`). Event groups are business-friendly names that group multiple specific events for easier automation management.
For complete documentation, see: **[Events Reference →](/docs/platform/events/overview)**
:::
### Pickup Reminder Automation
Create an automated workflow that triggers pickup reminders for packages delivered to parcel shops or lockers that haven't been collected within a specified timeframe.
## Inserting the tracking page link
To include the tracking page link in your Brevo transactional emails you should use dynamic content with `order_number` and `zip_code` variables, so that your customers always receive their personalised link:
For emails triggered through Brevo:
### Karla events
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ params.order_number }}&zipCode={{ params.zip_code }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ params.order_number }}&zipCode={{ params.zip_code }}&ref=karla
```
### Shipping Confirmation
Triggered by external events from your shop system.
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{ params.context.order.order_number }}&zipCode={{ params.context.order.address.zip_code }}&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{ params.context.order.order_number }}&zipCode={{ params.context.order.address.zip_code }}&ref=karla
```
:::tip
A `slug` is your unique identifier that represents your shop within the Karla system. This is used to properly route tracking information and ensure that shipment data is associated with the correct merchant account.
In addition, you can use `{{ params.event_data.order_number }}` and `{{ params.event_data.zip_code }}` to get the same parameters. See /docs/platform/events/overview#payload-envelope for more info.
:::
## Testing the automations
Once you've set up the automations and the respective emails it is important you make sure that the integration is working as expected.
In the Email Template Editor go to Preview & Test functionality.
There make sure that in the contact data you see the information from the profiles from your shop and not from Karla's test events. These should be infos like customer name, order number, shipping address etc.
:::warning
You will see this information only after you have integrated your shop and Brevo with Karla. [More on shop integrations](/docs/guides/shops/overview)
:::
If you want to see how your customers will receive the emails, you can send a test email to your email address.
### Putting the automations live
After you have tested your automations, you can put them live upon the agreed go-live date.
:::warning
Make sure you have configured the proper sending settings and have disabled any frequency caps for transactional emails, so that all of your customers receive their shipping updates.
:::
## Event Groups
Karla provides the following **event groups** to your Brevo instance for building automations. These are business-friendly groupings that make it easier to create targeted campaigns without dealing with individual event names.
:::info Event Groups vs Webhook Patterns
Event groups are specifically designed for **Brevo integration** and are different from webhook ref patterns:
- **Event Groups**: Business-friendly names, prefixed by `karla_` (e.g., `karla_shipment_delivered`)
- **Webhook Refs**: Technical identifiers (e.g., `shipments/delivered/SUCCESSFULLY_DELIVERED`)
For complete documentation of all events, ref patterns, and event groups, see: **[Events Reference →](/docs/platform/events/overview)**
The event group (without the `karla_` prefix) is also available in the `event_group` variable `{{ params.event_group }}`.
:::
### Claims
For any processed claim (e.g. damaged package, package not found...).
See [Claims](https://api.gokarla.io/public/redoc#tag/Claim).
- `karla_created`
- `karla_updated`
:::note
Claim events do **not** carry the `shipment_`-style group name that shipment
events do — they arrive in Brevo as `karla_created` and `karla_updated`. Build
your claim automations on those two names.
:::
### Shipments
For any processed shipment update:
| Event Group | Description | Use Case |
| --------------------------------------------------------- | ------------------------------ | ------------------------------ |
| `karla_shipment_pre_transit` | Package prepared for shipping | Confirmation emails |
| `karla_shipment_in_transit` | Package moving through network | Journey updates |
| `karla_shipment_carrier_delay` | Carrier-reported delays | Proactive communication |
| `karla_shipment_damaged` | Package damage reported | Customer service outreach |
| `karla_shipment_out_for_delivery` | Package out for delivery | Delivery notifications |
| `karla_shipment_delivered` | Successful delivery | Delivery confirmations |
| `karla_shipment_delivered_all_events` | All delivery variations | Comprehensive delivery flows |
| `karla_shipment_delivered_to_letterbox` | Delivered to letterbox | Specific delivery method |
| `karla_shipment_delivered_to_neighbour` | Delivered to neighbor | Neighbor delivery notification |
| `karla_shipment_delivered_to_parcel_locker` | Delivered to parcel locker | Pickup instructions |
| `karla_shipment_delivered_to_parcel_shop` | Delivered to pickup point | Pickup notifications |
| `karla_shipment_delivery_failed` | Delivery attempt failed | Retry communications |
| `karla_shipment_delivery_failed_address_issue` | Address problems | Address correction requests |
| `karla_shipment_delivery_failed_forwarded_to_parcel_shop` | Forwarded to pickup | Alternative pickup location |
| `karla_shipment_delivery_second_attempt` | Reattempting delivery | Second attempt notifications |
| `karla_shipment_not_picked_up_then_returned` | Not picked up, returned | Return notifications |
| `karla_shipment_refused_then_returned` | Customer refused package | Return processing |
| `karla_shipment_failed_returned` | Package returned to sender | Return confirmations |
| `karla_shipment_picked_up` | Successfully picked up | Pickup confirmations |
| `karla_shipment_delayed_due_to_customer_request` | Customer requested delay | Confirmation of delay request |
### Recommended Automation Priority
**High Priority** (Essential automations):
1. `karla_shipment_in_transit` - Keep customers informed
2. `karla_shipment_out_for_delivery` - Delivery readiness
3. `karla_shipment_delivered` - Delivery confirmation
4. `karla_shipment_carrier_delay` - Proactive communication
5. `karla_shipment_delivered_all_events` - Any delivery event
**Medium Priority** (Enhanced experience):
1. `karla_shipment_delivered_to_parcel_shop` - Pickup instructions
2. `karla_shipment_delivery_failed` - Retry coordination
3. `karla_shipment_damaged` - Customer service escalation
**Lower Priority** (Edge cases):
1. `karla_shipment_not_picked_up_then_returned` - Return processing
2. `karla_shipment_failed_returned` - Return confirmation
3. `karla_created` - Claims management
## Common Use Cases
### Post-Delivery Review Request
**Event Group**: `karla_shipment_delivered`
**Timing**: 2-3 days after delivery
**Content**: Thank you message + review request
### Pickup Reminder
**Event Group**: `karla_shipment_delivered_to_parcel_shop`
**Timing**: Immediate + daily reminders
**Content**: Pickup location, hours, deadline
### Delivery Issue Resolution
**Event Group**: `karla_shipment_delivery_failed`
**Timing**: Immediate
**Content**: Failed reason, next steps, support link
### Proactive Delay Communication
**Event Group**: `karla_shipment_carrier_delay`
**Timing**: As soon as delay detected
**Content**: New ETA, apology, compensation if applicable
## Best Practices
### 1. Email Content Guidelines
- **Be Specific**: Reference the exact delivery status
- **Include CTAs**: Add tracking links and next steps
- **Personalize**: Use customer and order data available from the event
- **Mobile-Optimize**: Most tracking emails are read on mobile
### 2. Testing Recommendations
1. Test each event group automation separately
2. Verify dynamic content populates correctly
3. Check email rendering across devices
4. Monitor delivery rates and engagement
## Troubleshooting
### Events Not Triggering Emails
1. Verify event group name matches exactly (case-sensitive)
2. Check integration credentials are active
3. Confirm automation is published in Brevo
4. Test with Karla test events
### Missing Data in Emails
1. Ensure all dynamic content variables match the event data
2. Check parameter syntax (`{{ params.field_name }}`)
3. Verify contact data mapping
### Email Delivery Issues
1. Check Brevo sending logs
2. Verify customer email addresses
3. Review spam folder placement
4. Check domain authentication (SPF/DKIM)
## Support
- **Karla Integration Support**: [support@gokarla.io]
- **Brevo Technical Support**: Refer to your Brevo account manager
- **Technical Documentation**: [Karla Events](/docs/platform/events/overview)
## Next Steps
1. Identify which event groups align with your communication strategy
2. Create automations for your priority events
3. Design and test email workflows
4. Monitor performance and optimize
---
## Braze
Source: https://gokarla.io/docs/guides/notify/integrations/braze
# Braze
:::info
The Braze integration allows Karla to send delivery and claims events as [custom events](https://www.braze.com/docs/user_guide/data/activation/custom_data/custom_events) to your Braze account, so you can build [Canvas](https://www.braze.com/docs/user_guide/engagement_tools/canvas) workflows for transactional emails.
:::
## What we need from you
To connect Karla to your Braze account, we need two things:
1. A **REST API Key** with the `users.track` permission
2. Your **Braze REST Endpoint URL** (e.g., `https://rest.fra-01.braze.eu`)
Follow the steps below to create these in your Braze dashboard.
## Setup
### 1. Open Braze Settings
Navigate to your Braze dashboard, click the **Settings** icon in the top navigation bar, and select [APIs and Identifiers](https://www.braze.com/docs/user_guide/administrative/app_settings/api_settings_tab) from the sidebar.
### 2. Create a REST API Key
In the **REST API Keys** section, click `Create New API Key`. Name it **Karla Integration** for easy identification.
### 3. Assign the required permission
Select the **`users.track`** permission. This is the only permission Karla needs. It allows us to send custom events to your Braze instance via the [`/users/track`](https://www.braze.com/docs/api/endpoints/user_data/post_user_track/) endpoint.
### 4. Save and copy
Click `Save`. **Copy the API key immediately** — it cannot be viewed again after you navigate away.
:::warning
Once created, a REST API key's permissions cannot be edited. If you need to change permissions, create a new key and replace the old one.
:::
### 5. Find your REST Endpoint URL
On the same **APIs and Identifiers** page, locate your **REST Endpoint URL**. It will look like `https://rest.fra-01.braze.eu` or `https://rest.iad-03.braze.com`, depending on your [Braze instance](https://www.braze.com/docs/api/basics/#endpoints).
### 6. Configure in Karla
In the [Karla portal](https://portal.gokarla.io/), go to `Settings` > `Integrations` > `Braze`.

1. Paste your **REST API Key**
2. Enter your **REST Endpoint URL**
3. Click **Save**
## How it works
Once connected, Karla sends [custom events](https://www.braze.com/docs/user_guide/data/activation/custom_data/custom_events) to Braze every time a shipment or claim status changes. All events are prefixed with `karla_` (e.g., `karla_shipment_delivered`).
You can then create [Canvas](https://www.braze.com/docs/user_guide/engagement_tools/canvas) workflows that trigger on these events to send transactional emails to your customers.
### Recommended event groups to start with
These 7 event groups cover the most important delivery scenarios:
| Event group | When it fires |
| -------------------------------------------- | -------------------------------------------------------------- |
| `karla_shipment_in_transit` | Shipment is on its way |
| `karla_shipment_out_for_delivery` | Shipment is out for delivery |
| `karla_shipment_delivered_all_events` | Any delivery event (delivered, to neighbor, parcel shop, etc.) |
| `karla_shipment_carrier_delay` | Carrier reports a delay |
| `karla_shipment_damaged` | Shipment is damaged |
| `karla_shipment_not_picked_up_then_returned` | Customer didn't pick up, returned to sender |
| `karla_shipment_failed_returned` | Delivery failed, returned to sender |
For the full list of event groups and their properties, see the [Events Reference](/docs/platform/events/overview).
## Creating a Canvas workflow
1. Go to `Messaging` > `Canvas` and click **Create Canvas**
2. Set the entry type to **Action-Based** and the trigger to **Perform Custom Event**
3. Select the Karla event you want (e.g., `karla_shipment_delivered`)
4. Build your message using event properties with Liquid syntax:
```liquid
{{canvas_entry_properties.${order_number}}}
{{canvas_entry_properties.${tracking_number}}}
{{canvas_entry_properties.${carrier}}}
{{canvas_entry_properties.${carrier_display_name}}}
{{canvas_entry_properties.${expected_delivery_date}}}
```
:::tip Which carrier property to use
`carrier` is the internal routing reference (e.g. `dhl-germany`).
`carrier_display_name` is the customer-safe label (e.g. `DHL`) — use that one
in anything a customer reads.
:::
For detailed Canvas setup instructions, see the [Braze Canvas documentation](https://www.braze.com/docs/user_guide/engagement_tools/canvas).
## Inserting the tracking page link
Use Liquid personalization to include a tracking page link in your emails. Replace `slug` with your Karla shop identifier:
```liquid title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber={{canvas_entry_properties.${order_number}}}&zipCode={{canvas_entry_properties.${zip_code}}}&ref=karla
```
```liquid title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber={{canvas_entry_properties.${order_number}}}&zipCode={{canvas_entry_properties.${zip_code}}}&ref=karla
```
## Going live
:::warning
Make sure you have disabled any [frequency caps](https://www.braze.com/docs/user_guide/engagement_tools/campaigns/building_campaigns/rate-limiting/#frequency-capping) for transactional emails so that all customers receive their shipping updates.
:::
## Support
- **Karla Integration Support**: [support@gokarla.io]
- **Braze Documentation**: [Braze Canvas Guide](https://www.braze.com/docs/user_guide/engagement_tools/canvas)
---
## Emarsys
Source: https://gokarla.io/docs/guides/notify/integrations/emarsys
# Emarsys
:::info
The Emarsys integration allows Karla to provide your Emarsys account with triggers of any sort, like shipment notifications or claims.
:::
## Steps
### 1. Open Emarsys & navigate to Administration
Navigate to your Emarsys instance and click on `Management` and `Security Settings`.

### 2. Access API Credentials
In `Security Settings`, select `API Credentials` to create new API access.

### 3. Generate API Credentials
Click on `Create API Credentials` and select `OpenID Connect`.
Create new API credentials and configure the necessary permissions.

#### Core
Permissions that enable the core notify functionality:
- **Contact Management**: create and update contact profiles
- **Event Tracking**: send custom events to your Emarsys account
- **Email Campaigns**: trigger automated email campaigns
These permissions are mandatory to have the minimum notification functionality working:
- `contact.create`: will create contact emails if not existing in the system
- `contact.get`
- `contact.getdata`
- `contact.list`
- `contact.lookup`
- `externalevent.create`: will create `karla_*` custom events
- `externalevent.delete`
- `externalevent.get`
- `externalevent.list`
- `externalevent.trigger`
- `externalevent.update`
- `externalevent.usages`
- `field.get`
- `field.list`
- `field.multichoice.list`
- `field.singlechoice.get`
- `field.singlechoice.lang.list`
- `field.singlechoice.trans.list`
#### Campaigns
Optional, only required to enable the following functionality:
- **Segments**: access segment data for targeted campaigns
- **Contact Lists**: access list of contacts for targeted campaigns
Enable the following in the permissions section for the API credential:
- `contactlist.contact.count`
- `contactlist.contact.get`
- `contactlist.contact.ids`
- `contactlist.contact.list`
- `contactlist.contact.lookup`
- `contactlist.contact.lookup.batch`
- `contactlist.list`
- `combinedsegment.get`
- `combinedsegment.list`
- `combinedsegment.test.get`
- `combinedsegment.universal.get`
- `combinedsegment.universal.list`
- `segment.contact.count`
- `segment.contact.list`
- `segment.contact.lookup`
- `segment.criteria.get`
- `segment.get`
- `segment.list`
### 4. Set up the API Credentials
Copy both the `Client ID` and `Client Secret` from the generated credentials.
In our [portal](https://portal.gokarla.io/), navigate to `Settings` > `Integrations`, and select `Emarsys`.

Paste the `Client ID` and `Client Secret` and click on `Save`.

Once the key has been saved successfully, you can toggle the integration settings.

## Building Emarsys Programs
Our Emarsys integration will automatically create external event names prefixed with `karla_`.
.
From there, you can create automation programs relying on these events to configure your own email flows.

### Pickup Reminder Program
Create an automated program that triggers pickup reminders for packages delivered to parcel shops or lockers that haven't been collected within a specified timeframe.
## Inserting the tracking page link
To include the tracking page link in your Emarsys transactional emails you should use dynamic content with `order_number` and `zip_code` variables, so that your customers always receive their personalised link:
For emails triggered through Emarsys:
### Karla events
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber=$order_number$&zipCode=$zip_code$&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber=$order_number$&zipCode=$zip_code$&ref=karla
```
### Shipping Confirmation
Triggered by external events from your shop system.
```json title="Karla hosted tracking page"
https://app.gokarla.io/track/slug?orderNumber=$order_number$&zipCode=$shipping_zip$&ref=karla
```
```json title="Embedded tracking page"
https://yourshop.com/pages/tracking?orderNumber=$order_number$&zipCode=$zip_code$&ref=karla
```
:::tip
A `slug` is your unique identifier that represents your shop within the Karla system. This is used to properly route tracking information and ensure that shipment data is associated with the correct merchant account.
:::
## Testing the programs
Once you've set up the programs and the respective emails it is important you make sure that the integration is working as expected.
In the Email Template Editor go to Preview & Test functionality.
There make sure that in the contact data you see the information from the profiles from your shop and not from Karla's test events. These should be infos like customer name, order number, shipping address etc.
:::warning
You will see this information only after you have integrated your shop and Emarsys with Karla. [More on shop integrations](/docs/guides/shops/overview)
:::
If you want to see how your customers will receive the emails, you can send a test email to your email address.
### Putting the programs live
After you have tested your programs, you can put them live upon the agreed go-live date.
:::warning
Make sure you have configured the proper sending settings and have disabled any frequency caps for transactional emails, so that all of your customers receive their shipping updates.
:::
## Event Groups
Karla provides the following **event groups** to your Emarsys instance for building programs. These are business-friendly groupings that make it easier to create targeted campaigns without dealing with individual event names.
:::info Event Groups vs Webhook Patterns
Event groups are specifically designed for **Emarsys integration** and are different from webhook ref patterns:
- **Event Groups**: Business-friendly names, prefixed by `karla_` (e.g., `karla_shipment_delivered`)
- **Webhook Refs**: Technical identifiers (e.g., `shipments/delivered/SUCCESSFULLY_DELIVERED`)
For complete documentation of all events, ref patterns, and event groups, see: **[Events Reference](/docs/platform/events/overview)**
:::
### Recommended Program Priority
**High Priority** (Essential programs):
1. `karla_shipment_in_transit` - Keep customers informed
2. `karla_shipment_out_for_delivery` - Delivery readiness
3. `karla_shipment_delivered` - Delivery confirmation
## Template variables
```text
Tracking number: {{event.global.tracking_number}}
Tracking URL (Carrier URL): {{event.global.tracking_url}}
Order Number: {{event.global.order_number}}
Zip Code: {{event.global.zip_code}}
Carrier Name: {{event.global.carrier}}
Shipping Address: {{event.global.shipping_address}}
Pick up Address: {{event.global.pick_up_address}}
Pick up until Datum: {{event.global.pick_up_until}}
Neighbour Name: {{event.global.neighbour_name}}
Total Order Value: {{event.global.total_order_value}}
Order Currency: {{event.global.order_currency}}
Customer ID: {{event.global.external_customer_id}}
External Order ID: {{event.global.external_order_id}}
Preferred Delivery Date: {{event.global.preferred_delivery_date}}
Customer First Name: {{event.global.customer_first_name}}
Customer First Name: {{event.global.customer_last_name}}
Customer Country: {{event.global.customer_country}}
```
---
## Inxmail
Source: https://gokarla.io/docs/guides/notify/integrations/inxmail
# Inxmail
## Overview
Inxmail is a professional email marketing platform that can integrate with Karla to trigger automated email workflows based on delivery events throughout the customer journey. This guide explains how to configure Inxmail templates to receive and process Karla events.
## How It Works
1. **Event Generation**: Karla generates events throughout the delivery journey
2. **Event Transmission**: When events occur, Karla sends them to Inxmail using your configured integration (events have to be created in Inxmail first)
3. **Template Matching**: Inxmail matches incoming events to templates based on the event group
4. **Email Workflow**: Your configured email workflows are triggered automatically
## Prerequisites
- Active Inxmail account with API access
- Karla integration credentials (configure your Inxmail integration in [portal](https://portal.gokarla.io))
- Understanding of [Karla Events](/docs/platform/events/overview)
## Template Configuration
### Base Template Structure
Every Karla event template in Inxmail must follow this XML structure:
```xml title="Base Event Template"
{event_group}Customer.EmailOrderOrderNumberOrderNumberUrlEncodedOrderNameTotalOrderPriceOrderCurrencyOrderStatusUrlExternalIdCustomerEmailNameCountryZipCodeShippingAddressExternalCustomerIdShipmentTrackingNumberTrackingUrlCarrierName
```
### Important: Event Group Configuration
The `{event_group}` placeholder in the template must be replaced with the specific event group you want to listen to. Each event group requires its own template in Inxmail.
## Available Event Groups
Karla provides the following event groups that you can configure templates for:
### Delivery Events
| Event Group | Description | Use Case |
| ------------------------------------- | ------------------------------ | ------------------------------------------- |
| `shipment_delivered` | Package successfully delivered | Send delivery confirmation, request reviews |
| `shipment_delivered_all_events` | All delivery variations | Comprehensive delivery tracking |
| `shipment_delivered_to_neighbour` | Left with neighbor | Notify about neighbor delivery |
| `shipment_delivered_to_letterbox` | Left in letterbox | Confirm letterbox delivery |
| `shipment_delivered_to_parcel_shop` | Ready at pickup location | Pickup reminder with location details |
| `shipment_delivered_to_parcel_locker` | In parcel locker | Locker code and pickup instructions |
| `shipment_picked_up` | Customer collected package | Confirm successful collection |
### Transit Events
| Event Group | Description | Use Case |
| --------------------------- | -------------------------------- | ---------------------------------------- |
| `shipment_pre_transit` | Order processed, awaiting pickup | Order confirmation, packing notification |
| `shipment_in_transit` | Package in carrier network | Shipping updates, ETA communication |
| `shipment_out_for_delivery` | Out for final delivery | Same-day delivery alerts |
### Issue Events
| Event Group | Description | Use Case |
| --------------------------------------------------- | ----------------------------- | ----------------------------- |
| `shipment_carrier_delay` | Delays in transit | Proactive delay notifications |
| `shipment_damaged` | Package damage reported | Damage incident communication |
| `shipment_delivery_failed` | Delivery attempt unsuccessful | Failed delivery instructions |
| `shipment_delivery_failed_address_issue` | Address problems | Request address clarification |
| `shipment_delivery_failed_forwarded_to_parcel_shop` | Redirected to pickup | New pickup location info |
| `shipment_delivery_second_attempt` | Redelivery scheduled | Second attempt notification |
### Return Events
| Event Group | Description | Use Case |
| -------------------------------------- | -------------------------- | ---------------------- |
| `shipment_not_picked_up_then_returned` | Not collected, returning | Missed pickup alerts |
| `shipment_refused_then_returned` | Customer refused delivery | Refusal follow-up |
| `shipment_failed_returned` | Package returned to sender | Return process updates |
### Customer Service Events
| Event Group | Description | Use Case |
| ----------- | ------------------------ | -------------------- |
| `created` | Customer submitted claim | Claim acknowledgment |
| `updated` | Claim status changed | Resolution updates |
:::note
Claim events use the bare ids `created` and `updated` — not the
`claim_`-prefixed names. Create your Inxmail event types with exactly those ids.
:::
### Special Events
| Event Group | Description | Use Case |
| ------------------------------------------ | ------------------------ | ----------------------------- |
| `shipment_delayed_due_to_customer_request` | Customer requested delay | Confirmation of delay request |
## Configuration Steps
### 1. Create Templates for Each Event Group
For each event group you want to monitor, create a separate template in Inxmail:
```xml title="Example: Delivery Confirmation Template"
shipment_delivered
```
```xml title="Example: Failed Delivery Template"
shipment_delivery_failed
```
:::note
You can configure one event with the template and then duplicate it later with a different event name.
:::
### 2. Configure Email Workflows
For each template, set up corresponding email workflows:
1. **Immediate Notifications**: For time-sensitive events (out for delivery, failed delivery)
2. **Delayed Communications**: For follow-ups (review requests post-delivery)
3. **Conditional Logic**: Different emails based on delivery method or location
### 3. Use Placeholder Data
In your email templates, use the placeholder data:
- `{{Order.OrderNumber}}` - Order reference
- `{{Order.TotalOrderPrice}}` - Order value
- `{{Customer.Name}}` - Recipient name
- `{{Customer.ZipCode}}` - Shipping address postal code
- `{{Shipment.TrackingUrl}}` - Direct tracking link
- `{{Shipment.CarrierName}}` - Carrier information
Check the template variables for more options.
## Best Practices
### 1. Event Selection Strategy
- **Start Small**: Begin with critical events (delivered, failed delivery)
- **Avoid Duplication**: Don't listen to overlapping event groups
- **Consider Frequency**: High-frequency events may need rate limiting
### 2. Email Content Guidelines
- **Be Specific**: Reference the exact delivery status
- **Include CTAs**: Add tracking links and next steps
- **Personalize**: Use customer and order data
- **Mobile-Optimize**: Most tracking emails are read on mobile
### 3. Testing Recommendations
1. Test each event group template separately
2. Verify placeholder data populates correctly
3. Check email rendering across devices
4. Monitor delivery rates and engagement
## Common Use Cases
### Post-Delivery Review Request
**Event Group**: `shipment_delivered`
**Timing**: 2-3 days after delivery
**Content**: Thank you message + review request
### Pickup Reminder
**Event Group**: `shipment_delivered_to_parcel_shop`
**Timing**: Immediate + daily reminders
**Content**: Pickup location, hours, deadline
### Delivery Issue Resolution
**Event Group**: `shipment_delivery_failed`
**Timing**: Immediate
**Content**: Failed reason, next steps, support link
### Proactive Delay Communication
**Event Group**: `shipment_carrier_delay`
**Timing**: As soon as delay detected
**Content**: New ETA, apology, compensation if applicable
## Troubleshooting
### Events Not Triggering Emails
1. Verify event group ID matches exactly (case-sensitive)
2. Check integration credentials are active
3. Confirm template is published in Inxmail
4. Test with Karla test events
### Missing Data in Emails
1. Ensure all placeholders match the template structure
2. Check data type definitions (string vs double)
3. Verify customer email field mapping
### Email Delivery Issues
1. Check Inxmail sending logs
2. Verify customer email addresses
3. Review spam folder placement
4. Check domain authentication (SPF/DKIM)
## Support
- **Karla Integration Support**: support@gokarla.io
- **Inxmail Technical Support**: Refer to your Inxmail account manager
- **Technical Documentation**: [Karla Events](/docs/platform/events/overview)
## Next Steps
1. Identify which event groups align with your communication strategy
2. Create templates for your priority events
3. Design and test email workflows
4. Monitor performance and optimize
---
## WhatsApp
Source: https://gokarla.io/docs/guides/notify/integrations/whatsapp
# WhatsApp
:::note
Disclaimer: This article describes the Karla x Chatarmin integration for WhatsApp shipping notifications. The same approach (where Karla events are first sent to Klaviyo and then to WhatsApp providers through webhooks) can be used for other providers as well.
:::
## **What’s required to get started with your Karla x Chatarmin integration**
In order to make Karla’s shipping triggers available in Chatarmin, you need to
1. Use Karla’s `Notify` Package, which includes providing shipment triggers to Klaviyo / Chatarmin
2. Integrate your Chatarmin account with your Klaviyo account
## Step-by-Step Guide: How to use Karla’s shipment triggers for Chatarmin WhatsApp notifications
## **Step-by-step Karla Chatarmin installation**
### **1. Create WhatsApp Template (e.g. ‘delivered_to_parcelshop’)**
- Select “Template Type” = Utility (as it will be used for transactional purposes)
- Enter a text for the appropriate use case (e.g. a reminder to pick up the parcel at the parcelshop)
- Add a button, selecting “Ppen website” and enter any URL (don’t worry about which URL you put in there → will be updated when setting up the flow later anyways)
- Save the template. It will be reviewed and approved within a few of seconds.

### **2. Create Chatarmin Flow**
- Go to flows, click on ‘Create new flow’ and ‘Create from scratch’. Give it a name, description (optional) and continue.
- Select ‘Klaviyo Webhooks’ as a starting point and open the corresponding flow in Klaviyo.

- Give it a name, description (optional) and continue.

- Select ‘Klaviyo Webhooks’ as a trigger and open the corresponding flow in Klaviyo.


### **3. Configure webhook in Chatarmin & Klaviyo**
**Follow these steps:**
- In the Klaviyo flow, add “webhook” as action following the respective shipment trigger and enter the Chatarmin webhook information: (Destination) URL, Key & Value from your Chatarmin flow into the Klaviyo fields and give the Webhook a name.
- Adjust the ‘Payload’ in both Klaviyo’s ‘JSON payload field’ and Chatarmin’s webhook ‘Payload body’. They have to be identical, including the following variables:
```json
{
"email": "{{ person.email }}",
"phone": "{{ person.phone_number|default:'' }}",
"firstname": "{{ person.first_name|default:'' }}",
"carrier": "{{ event.carrier|default:'' }}",
"order_number": "{{ event.order_number|default:'' }}",
"tracking_number": "{{ event.tracking_number|default:'' }}",
"carrier_url": "{{ event.tracking_url|default:'' }}",
"zip_code": "{{ event.zip_code|default:'' }}",
"karla_trackpage_url": "{{ event.order_number|default:'' }}&zipCode={{ event.zip_code|default:'' }}&ref=karla"
}
```
:::warning
**Important information on the payload:**
- Depending on the respective Karla trigger event, you can also select more available event properties and send them in the payload, e.g. for parcelshop, parcel locker & neighbour address.
- The first part of the karla_trackpage_url needs to be adapted to your tracking page url. The latter part stays the same `(xxx?orderNumber=\{\{ event.order_number|default:'' \}\}&zipCode=\{\{ event.zip_code|default:'' \}\}&ref=karla).`
:::


Enter the (Destination) URL, Key & Value from your Chatarmin flow into the Klaviyo fields and give the Webhook a name.

JSON body in Klaviyo

_Payload Body in Chatarmin_
:::warning
Depending on the respective Karla trigger event, you can also select more available variables and send them in the payload, e.g. for parcelshop, parcellocker & neighbour address.
:::
### **4. Save the webhook and build your Chatarmin flow**
- Save the webhook in Klaviyo (and set in live) and Chatarmin
- In Chatarmin's flow builder, select 'Send campaign' as intended action.
- Pick the template you've set up in Step 1 and select "API: karla_trackpage_url" for the button.
- Save the flow and select ‘Send campaign’ as intended action. Select your campaign template in the drop-down and replace the button URL with the karla_trackpage_url


### **5. Use the touchpoint to generate a double opt-in by extending your flow with a consent message**

### **6. Publish the flow and set it active. Well done! 🤩**
## More on this topic
### WhatsApp Newsletter Signup via Tracking Page (Chatarmin)
---
# Resolve
> Customer service and embedding options
## Overview
Source: https://gokarla.io/docs/guides/resolve/overview
# Resolve
Customers resolve damaged, missing, and returned orders themselves — no
ticket, no wait. Structured data flows to your team; automations take care of
the rest.
## Try it
A live resolve flow with sample data. Pick an issue, walk through the
steps — the whole experience is fully brand-customizable in the portal.
## The flows
Resolve ships seven ready-made flows. Each one is a guided path the customer
walks through: pick the issue, give us what we need (a photo, the affected
items, a short note), tell us how they'd like it resolved. You decide which
flows to expose and how strict each one is.
Item arrived damaged or broken. Customer uploads a photo, picks the affected
items, describes the issue. Resolution preference: refund, replacement, or
keep with reward — you choose which options to offer.
Marked delivered but missing. Customer confirms the address and checks with
neighbors before triggering a carrier investigation, replacement, or refund.
Order arrived, but something's missing from the box. Customer picks which
items never showed up.
Got the package, wrong contents. Customer flags the mismatch and uploads
proof.
Wrong size, changed mind, doesn't fit. Customer selects items and gives a
reason — Karla can generate the return label on the spot, right in the flow.
Product arrived intact, but didn't meet expectations. Captures the feedback
as a structured claim instead of an angry email.
A catch-all for anything outside the other flows. Becomes a structured
ticket your team can pick up.
## What makes it work
Most claims complete in 2–3 steps. No account needed — order number + ZIP
(or a secure token) is enough.
Show or hide flows based on shipment phase, time since delivery, items in
the order — or just turn them off. Every flow is a set of steps you can
rearrange, tighten, or relax.
Every claim lands as a structured payload (photos, affected items, customer
preference) your team or helpdesk can act on instantly.
Fully themable in the portal. Multi-language; fallbacks handled
automatically.
## Where to next
- [Flows and customization](/docs/guides/resolve/flows-and-customization) —
what you can configure: steps, toggles, guardrails, and branding.
- [Shop connection](/docs/guides/resolve/shop-connection) — what Resolve
needs from your shop to do its job.
- [Data processing](/docs/guides/resolve/data-processing) — what a claim
contains and where it lives.
- [Integration and automation](/docs/guides/resolve/integration-and-automation)
— helpdesk routing, custom outputs, and claim automation overview.
- [Claim automation](/docs/guides/resolve/claim-automation) — per-merchant
rule sets for automated refunds and replacements.
- [Returns](/docs/guides/resolve/returns) — let Karla generate return labels
in the flow (PDF download plus a QR code, also emailed to the customer), or
hand off to your returns portal.
- [Helpdesk integrations](/docs/guides/resolve/integrations/overview) —
connect Zendesk natively or route claims to any helpdesk via webhooks.
- [Integrate in your shop](/docs/guides/resolve/integrate-in-your-shop) —
embed the resolve widget on your own domain.
- Got a unique flow in mind?
[Talk to us](mailto:hello@gokarla.io) about custom automations.
---
## Flows and customization
Source: https://gokarla.io/docs/guides/resolve/flows-and-customization
# Flows and customization
Resolve is a kit of building blocks. The flows below come ready to use, the
steps inside them are rearrangeable, and the guardrails around them are all
optional. This page is a tour of what you can switch on, what you can shape,
and where each piece earns its keep.
The general rule: if you see a behavior described here, you can turn it off.
If you see a number, you can change it. If you see a step, you can move it
or skip it.
## The seven flows
Resolve ships with seven flows, each designed around one type of issue. You
choose which ones to expose; everything else stays hidden.
| Flow | When customers reach for it |
| ------------------- | ------------------------------------------------- |
| **Defective** | Item arrived damaged or broken |
| **Not received** | Tracking says delivered, customer didn't get it |
| **Missing product** | Package arrived, something's missing from the box |
| **Wrong product** | Package arrived with the wrong contents |
| **Return** | Wrong size, changed mind, doesn't fit |
| **Dissatisfied** | Item is fine but didn't meet expectations |
| **Support** | Catch-all for anything outside the other flows |
Each flow is a guided sequence of steps: pick the issue, identify the
affected items, give us the evidence we need, choose how you'd like it
resolved. The customer never sees the ones you've turned off.
## The steps inside a flow
A flow is built out of steps, and most steps are optional. The big ones:
- **Issue selection** — the entry point. Lists the flows you've enabled. You
control the order the issues appear in and can group them into "Product
Issues" and "Other" — rearrange both with drag-and-drop in the portal.
- **Product selection** — pick which line items are affected and how many
units. Smart defaults based on what's in the order.
- **Image upload** — proof of the issue. You can require a minimum number of
pictures per item, mandate a separate "whole package" shot, or leave it
optional.
- **User description** — the customer's note. You decide whether it's
required, set minimum and maximum character counts, and whether the
resolution preference (refund vs. replacement) shows up here.
- **Resolution preference** — how the customer wants it resolved. Choose
which options they can pick — reorder, refund, keep with reward — under
**Resolve → Features → Resolution options** (refund and reorder by
default). Available per flow type — for example, you might offer it for
defective claims but not for a support ticket.
- **Signature** — for flows that need acknowledgement (return drop-offs,
carrier investigations).
- **Submission** — the closing screen. Can carry a custom message or link
out to your own confirmation page.
- **Information** — drop a static information panel anywhere in the flow
(FAQ link, policy reminder, pre-flow disclaimer).
- **Custom prompt** — ask a custom multiple-choice question at any point
("How did you discover the damage?") and capture the answer in the claim.
- **Handoff step** — transfer the customer to your returns portal or another
third-party tool, with optional order data in the URL. See
[Returns](./returns) for how this works in practice.
You don't have to use all of them. A minimal flow can be three steps; a
detailed one can be eight. We'll help you find the right shape for your
operation.
## Conditional behavior
Most of what's in Resolve can be made conditional. Show a flow only when it
makes sense; hide it the rest of the time.
- **By shipment phase.** Only show "not received" once tracking marks the
shipment as delivered. Only show "return" once the customer has actually
received the order.
- **By time elapsed.** Only show a flow after a number of hours has passed
since a phase change — for example, only let customers report
non-delivery 24 hours after the carrier marked it delivered.
- **By selected items.** Require at least N items selected before a flow
becomes available.
- **By selected quantities.** Same idea, but counting total units rather
than distinct line items.
- **By delivery status.** Split a single flow into "delivered" and "not yet
delivered" branches that ask different questions and end in different
resolutions.
These toggles compose: you can require both "delivered for at least 12
hours" and "at least 1 item selected" before the defective flow becomes
clickable.
## Guardrails for your operations team
Resolve gives the customer a clean self-service experience, but you still
want sensible limits on the back end. A few of the levers:
- **Block duplicate submissions.** Stop customers from filing more than one
claim per order. Off by default — flip it on if you'd rather not have
duplicate tickets to triage. If you'd rather let the customer submit
again, leave it off.
- **Mandatory descriptions with min/max characters.** Keep claims
actionable. Set a minimum to weed out one-word submissions, a maximum to
keep things readable.
- **Minimum images per item.** Require enough proof for your ops team to
make a decision without going back to the customer.
- **Warranty windows.** Cap product selection in the defective flow to
items still within warranty.
- **Resolution preference per flow.** Show "refund or replacement" for
defective claims; hide it for support tickets where you'd rather decide
case by case.
## Branding and language
Resolve renders inside your brand, not next to it.
- **Colors, background, and logo.** Configure the palette, background type
(solid color or image), and the logo shown on the side panel. The
customer never leaves the brand.
- **Themed for desktop and mobile.** A split-screen layout on larger
screens, a stacked layout on phones — handled automatically.
- **Multi-language.** All flow copy is translatable; missing translations
fall back gracefully. You can edit translations directly in the portal.
- **Exit redirect.** Send the customer back to your shop, your tracking
page, or anywhere else once the flow ends.
## Editing all of this
Most of what's described here is editable directly in the
[Merchant Portal](https://portal.gokarla.io) — the Resolve preview page lets
you adjust style, toggle features, and edit translations side by side with a
live preview of the customer experience.
**After submit**, [claim automation](./claim-automation) rules run in the
portal under **Settings → Claim Automation** — separate from the customer-facing
flow, but driven by the same structured claim data (reason, preference, value,
shipment status). Deeper custom routing or multi-destination fan-out beyond the
rule builder is something we can set up with you. Talk to your account manager
when you have something specific in mind.
## Where to next
- [Integrate in your shop](./integrate-in-your-shop) — embed the resolve
widget on your own domain.
- [Data processing](./data-processing) — what lands where after the
customer submits.
- [Claim automation](./claim-automation) — rule sets for automated refunds
and replacements.
- [Portal → Resolve](/docs/guides/portal/resolve) — claims analytics and the
Claims table.
---
## Shop connection
Source: https://gokarla.io/docs/guides/resolve/shop-connection
# Shop connection
Resolve runs on top of your order data. Once your shop is connected to Karla,
every claim a customer submits is automatically tied to a real order, real
items, and the real fulfillment state — no copy-pasting, no lookups, no
ambiguity.
## What Resolve needs from your shop
To do its job, Resolve reads from the order context Karla already maintains
for tracking. Specifically:
- **Orders and line items** — to power the issue selection and let the
customer pick which items are affected.
- **Fulfillment status and shipments** — to know whether the order is in
transit, delivered, or stuck, and to gate flows accordingly (e.g. a "not
received" flow that only appears once a shipment is marked delivered).
- **Customer details** — to pre-fill the resolve UI and verify identity via
ZIP code or token.
- **Refund and replacement endpoints** — required for
[claim automation](./claim-automation). Karla issues refunds or triggers
replacements directly in your shop when a rule matches and safety gates pass.
This part is **Shopify-only** today: automated refunds and reorders are
executed against Shopify, so shops on other platforms can still collect and
route claims, but automation rules fall back to manual handling.
If your shop is already connected for tracking, Resolve has everything it
needs. If not, see [Shops](/docs/guides/shops/overview) to pick your platform
and connect.
## How customer lookup works
Customers don't sign in. Resolve identifies the order in one of two ways:
- **Order number + ZIP code** — the default. Lightweight, works for any
customer who has the order confirmation handy.
- **Token-authenticated link** — a secure, order-scoped link that Karla
embeds in the notifications it sends (shipping emails, tracking page URLs,
etc.). The token tells Resolve "this visitor is authenticated for this
specific order," which unlocks more sensitive operations.
Token lookup is enabled by default on every shop. You can also retrieve a
token-protected URL for any order through the public
[API](/docs/api-reference) and embed it in your own emails, support macros,
or post-purchase flows.
:::tip Tokens unlock more
Order-scoped actions (cancellations, address changes, and similar sensitive
flows) are reserved for token-authenticated sessions. The set of capabilities
behind the token keeps growing — anything you embed via a token-bearing link
will pick up new features automatically.
:::
## Where claims go
Once a customer submits a claim, Karla holds it as a structured record and
makes it available to you in three places:
- The **Claims** view in the [Merchant Portal](https://portal.gokarla.io) —
filter, inspect, and export.
- Any **helpdesk or workflow tool** you've wired up — via a native
integration or claim webhooks. See
[Helpdesk integrations](./integrations/overview) for setup options.
- The **Karla API** — pull claims programmatically alongside the originating
order and shipment.
## Talking to your systems
If you want Karla to deliver claims to your service desk or internal tooling,
see [Helpdesk integrations](./integrations/overview) for native connections
and webhook setup. For the payload shape, see
[Data processing](./data-processing).
A couple of operational notes that come up:
- **All traffic uses HTTPS** with TLS 1.2 or higher. Your endpoint needs a
valid, trusted certificate.
- **Static IP egress** is available as a premium add-on if your service desk
sits behind a firewall and you need to allow-list a fixed source. Talk to
your account manager if you need this.
---
## Data processing
Source: https://gokarla.io/docs/guides/resolve/data-processing
# Data processing
Every claim a customer submits through Resolve becomes a structured record —
not a free-form ticket. That structure is what unlocks automations,
helpdesk integrations, and analytics that actually mean something.
## What a claim contains
A claim is the full, machine-readable picture of what went wrong:
- **The order and its items** — the originating order, the specific line
items the customer flagged, and how many units are affected.
- **The reason** — which flow the customer entered (defective, return, not
received, etc.) and the specific reason within that flow.
- **The customer's preference** — refund, replacement, or whatever options
you exposed.
- **Evidence** — photos, signatures, free-text descriptions, answers to any
custom prompts you added.
- **Order context** — fulfillment status, shipment phase, carrier
information, the customer's address. Enough for your team or your
automation to make a decision without looking anything else up.
The complete shape lives in the [Claim API](/docs/api-reference). For event
payloads, see [Claim events](/docs/platform/events/claims).
## Where claims go
Once submitted, a claim is available everywhere you need it:
- **Merchant Portal** — the [Claims](/docs/guides/portal/resolve) view, with
filters, individual claim detail, and CSV export.
- **Service desk or helpdesk** — via a native integration (e.g.
[Zendesk](./integrations/zendesk), [Gorgias](./integrations/gorgias),
[Dixa](./integrations/dixa), [Kustomer](./integrations/kustomer), or
[Intercom](./integrations/intercom)) or
[claim webhooks](./integrations/webhooks). The payload is the same
structured record, ready to open as a ticket with all the context attached.
- **Karla API** — pull claims programmatically, joined with the originating
order and shipment.
- **Claim automation** — when enabled, Karla evaluates your
[rule set](./claim-automation) and may refund or reorder in your shop before
or alongside helpdesk routing.
- **Analytics** — every claim feeds the Claims Analytics dashboard:
breakdowns by reason, by carrier, by region, by product, by shipment
phase. The same data, rolled up to spot patterns.
Beyond Karla's own surfaces, the structured claim is what powers
[claim automation](./claim-automation), helpdesk routing, and any custom output
your operation needs. See [Integration and automation](./integration-and-automation)
for the full picture.
For the broader entity model, see [Orders](/docs/platform/orders) and
[Events](/docs/platform/events/overview).
---
## Integration and automation
Source: https://gokarla.io/docs/guides/resolve/integration-and-automation
# Integration and automation
Once a customer hits submit, the claim doesn't just sit in a database
waiting for someone to look at it. Karla runs a per-brand automation layer
that takes the structured claim, routes it to your tools, and — when your
rules allow it — closes it automatically in your shop.
## Claims, anywhere you want them
Every claim can reach your helpdesk in one of two ways:
- **Native integrations** — connect Zendesk, Gorgias, Dixa, Front, Kustomer, or
Intercom directly in the
[Karla portal](https://portal.gokarla.io). Karla authenticates with your instance
and creates tickets with the right fields, attachments, and customer
threading. No native helpdesk? An [email fallback](./integrations/email) sends claims to
your support inbox. See [Helpdesk integrations](./integrations/overview).
- **Webhooks** — point Karla at any HTTPS endpoint and receive the structured
claim payload described in [Data processing](./data-processing). You map it
to your helpdesk, or use a connector. See
[Webhooks](./integrations/webhooks).
Either way, your agents see a properly populated ticket — photos, affected
items, order context, resolution preference — not a JSON dump.
## Claim automation — rule-based refunds and replacements
For qualifying claims, you don't need an agent in the loop at all. Karla can
issue refunds and trigger replacement orders directly in your shop the moment
a claim matches your rules.
This is **self-serve and per merchant**. In the portal under
**Settings → Claim Automation**, you build an ordered **rule set**:
- **Logic checks** on claim reason, resolution preference, claimed value,
claimed quantity, and shipment status — combined with AND logic inside each
rule.
- **Refund**, **Reorder**, **Automate**, or **Manual** actions per rule,
evaluated **first-match-wins** from top to bottom.
- **Notification mode** — still create a helpdesk ticket when Karla automates,
or stay silent and resolve only in your shop.
- **Platform safety gates** — stock, address, duplicate-order, and shop errors
can still block automation even when a rule matches.
A rule can force the outcome — **Refund** or **Reorder** regardless of what
the customer asked for — or follow the customer's **resolution preference**
on the claim with **Automate**. **Manual** keeps the claim with your team.
:::tip Full setup guide
See [Claim automation](./claim-automation) for condition fields, example rule
sets, safety gates, API access, and troubleshooting.
:::
The goal is to get the predictable share of claims off your team's plate
without giving up control: you define the logic, Karla enforces it, and
anything that doesn't match (or fails a safety gate) lands with your agents.
## Custom transformations
Beyond self-serve claim automation and helpdesk routing, Karla can reshape
claims for specialized operations — often set up with your account team.
Claims rarely fit one shape. The same submission might need to become a
ticket in your helpdesk, a row in your warehouse, a refund in your shop,
and a PDF for a carrier dispute — all at once. The automation layer takes
care of that fan-out.
Common extensions merchants ask for:
- **DOR (Damage / Operations Report) documents** generated from claim data
for carrier disputes or internal audits. The carrier affidavit PDF for
not-received claims is self-serve — turn it on per helpdesk in
[Helpdesk integrations](./integrations/overview).
- **Custom payload shapes** for non-standard helpdesks, internal ticketing
systems, or BI pipelines.
- **Conditional routing** — send specific claim types to specific queues,
brands, regions, or warehouses beyond the portal rule builder.
- **Enrichment** — combine the claim with order, shipment, or customer
context before forwarding it on.
If you can describe what you want to happen when a claim comes in, we can
almost certainly wire it up. [Talk to us](mailto:hello@gokarla.io).
## Where to next
- [Claim automation](./claim-automation) — configure rule sets, safety gates,
and notification mode in the portal.
- [Helpdesk integrations](./integrations/overview) — connect Zendesk, Gorgias,
Dixa, Front, Kustomer, or Intercom, or route claims via webhooks.
- [Data processing](./data-processing) — the claim payload itself, and
where claims live in Karla.
- [Shop connection](./shop-connection) — refund and replacement prerequisites.
- [Integrate in your shop](./integrate-in-your-shop) — embedding the
resolve widget on your domain.
- [Portal → Resolve](/docs/guides/portal/resolve) — the Claims view and
analytics.
---
## Claim automation
Source: https://gokarla.io/docs/guides/resolve/claim-automation
# Claim automation
:::info
Claim automation lets you close Resolve claims without an agent in the loop.
You define ordered **rule sets** in the Karla portal — each rule checks claim
data with logic you control and picks what happens on a match: **refund** or
**reorder** directly, **automate** (follow the customer's resolution
preference), or route the claim to **manual** review. Rules are evaluated
top-to-bottom; the first match wins. Everything else falls through to your
team.
:::
## What you need
Before turning automation on:
- **Resolve enabled** on your Karla package.
- **A connected Shopify shop** — automated refunds and replacements are
executed in Shopify, so automation only completes for Shopify shops. Rules on
other platforms fall back to manual handling. See
[Shop connection](./shop-connection).
- **Portal admin access** — only admins can view and edit Claim Automation
settings.
- **Optional helpdesk integration** — useful when you want agents notified
even after an automated resolution. See
[Helpdesk integrations](./integrations/overview).
:::note
Claim Automation appears under **Settings** in the
[Karla portal](https://portal.gokarla.io/) for eligible shops. If you do not
see it, contact your account manager.
:::
## How a claim moves through automation
When a customer submits a Resolve claim, Karla evaluates your rule set against
the structured claim record — reason, resolution preference, claimed value,
shipment status, and the rest of the payload described in
[Data processing](./data-processing).
```text title="Evaluation flow"
Customer submits claim
→ Is claim automation enabled?
No → Manual handling (helpdesk ticket per your integration)
Yes → Walk rules top-to-bottom
→ First rule where ALL conditions match:
refund → Issue a refund in your shop
reorder → Create a replacement order in your shop
automate → Refund or reorder in your shop (per customer preference)
manual → Stop — manual handling
→ No rule matched → Manual handling
→ Safety gates may still override automation (see below)
→ Optional helpdesk notification (per your notification mode)
```
A matched rule's **action** decides the outcome:
| Action | What happens on a match |
| ------------ | -------------------------------------------------------------------------------- |
| **Refund** | Issue a refund — regardless of the customer's resolution preference |
| **Reorder** | Create a replacement order — regardless of the customer's resolution preference |
| **Automate** | Follow the customer's **resolution preference** on the claim (refund or reorder) |
| **Manual** | Stop — hand the claim to your team |
**Refund** and **Reorder** force the outcome regardless of any preference —
use them when you only ever offer one outcome. **Automate** follows the
`refund` or `reorder` preference **recorded on the claim** — which is not
always one the customer actively picked: claims submitted through the Resolve
widget always carry a preference, even when the picker is hidden (see
[Customer resolution preference](#customer-resolution-preference) for the
defaults). A claim with no recorded refund/reorder preference — for example
one created through another channel, or a `keep_with_reward` choice — has no
automated path under **Automate** and falls back to manual handling. You pick
which options customers can choose under
**Resolve → Features → Resolution options** in the portal — refund and
reorder are offered by default, keep with reward is opt-in.
## Configure rules in the portal
In the [Karla portal](https://portal.gokarla.io/), open
**Settings → Claim Automation**.
### Master controls
| Control | What it does |
| --------------------------- | ------------------------------------------------------------ |
| **Enable claim automation** | Master on/off for automated refund and reorder |
| **Notification mode** | Whether automated resolutions still create a helpdesk ticket |
**Notification mode** options:
- **Notify** — create an outcome ticket in your helpdesk so agents see what
Karla did (recommended when you want an audit trail alongside automation).
- **Silent** — resolve in your shop only; no ticket for automated outcomes.
### Rule sets
Rules are **ordered**. Karla evaluates them from top to bottom and stops at
the first match. Reorder rules with the up/down controls when priority matters.
Each rule has:
- **Action** — `Refund`, `Reorder`, `Automate`, or `Manual`
- **Conditions** — one or more checks; **all** must match (logical AND)
Use **Add rule** and **Add condition** to build your set. A claim that matches
no rule is handled manually — automation is strictly opt-in per matching rule.
:::tip Start conservative
Many merchants begin with a narrow **Automate** rule (e.g. low-value missing
product + refund preference) and a catch-all **Manual** rule at the bottom.
Expand automation as you gain confidence in the outcomes.
:::
## Condition fields and operators
Each condition compares one claim attribute to a value you set.
| Field | What it checks | Operators | Example |
| ------------------------- | ----------------------------------------------- | ---------------------------------------------------- | ---------------------------- |
| **Claim reason** | Which Resolve flow/reason the customer selected | equals, is one of | `missing_product` |
| **Resolution preference** | What the customer asked for | equals, is one of | `refund` |
| **Claimed value** | Monetary value of the claimed items | equals, below, below or equal, above, above or equal | `50` (auto-refund up to €50) |
| **Claimed quantity** | Total units claimed across the selected items | equals, below, below or equal, above, above or equal | `2` |
| **Shipment status** | Current shipment phase | equals, is one of | `delivered` |
**Claimed value** and **Claimed quantity** are numeric — they take a number (the
portal labels the box "Amount" and "Item count" respectively) and do not support
**is one of**.
### Claim reason values
| Value in portal | Typical flow |
| --------------------------- | --------------- |
| `damage` | Defective |
| `investigation` | Not received |
| `missing_product` | Missing product |
| `wrong_product` | Wrong product |
| `return` | Return |
| `dissatisfied_with_product` | Dissatisfied |
| `support` | General support |
:::note `partial_damage` is deprecated
Claims submitted with the older `partial_damage` reason are converted to
`damage` before they are stored, so a rule matching `partial_damage` can never
fire. Target `damage` instead — it covers both.
:::
### Shipment status values
**Shipment status** matches the shipment's current phase, entered as a plain
value: `order_created`, `order_processed`, `order_cancelled`, `in_transit`,
`in_delivery`, `collect`, `delivered`, `delivery_failed`, `returned`,
`return_created`, `return_transit`, `return_received`, or `return_failed`.
Use **is one of** when a rule should match multiple reasons, preferences, or
statuses (e.g. `missing_product` and `wrong_product`).
## Example rule sets
:::note Every rule needs at least one condition
A rule with no conditions is rejected when you save. You never need a
"catch-all" **Manual** rule at the bottom: a claim that matches no rule is
handled manually anyway. Add an explicit **Manual** rule only when you want to
stop evaluation _before_ a broader automation rule below it.
:::
### Always refund, no preference step
Force a refund for trusted claim types — works even when your flow never asks
the customer for a resolution preference.
1. **Refund** — `claim reason` equals `damage` AND `claimed value` below or
equal `100`
Anything else falls through to your team.
### Tiered value gates
Route low-risk claims to automation; keep high-value orders manual.
1. **Automate** — `claimed value` below or equal `75` AND
`resolution preference` equals `refund` AND `claim reason` is one of
`missing_product`, `wrong_product`
Claims above €75 match no rule and stay manual.
### Reason-based routing
Automate only the claim types your ops team trusts, and stop a specific reason
from reaching a broader rule below it.
1. **Manual** — `claim reason` equals `dissatisfied_with_product`
2. **Automate** — `claim reason` is one of `missing_product`, `wrong_product`
Because the first match wins, listing the **Manual** rule first keeps
dissatisfaction claims with your team even if you later widen rule 2.
### Replacement only when delivered
Honor the customer's reorder request only after delivery is confirmed.
1. **Automate** — `resolution preference` equals `reorder` AND `shipment status`
equals `delivered` AND `claimed value` below or equal `200`
### Small quantities only
Automate single-item claims and keep bulk claims under human review.
1. **Automate** — `claimed quantity` below or equal `2` AND `claim reason`
equals `missing_product`
## Safety gates
Your rules define **what Karla may attempt**. Karla still runs **platform
safety gates** before executing a refund or replacement — even when a rule
matches. If a gate fails, the claim falls back to manual handling and Karla
records why.
Common automatic fallbacks:
| Outcome | Meaning |
| -------------------------- | ----------------------------------------------------- |
| `manual_out_of_stock` | Replacement requested but inventory is not available |
| `manual_missing_address` | Shipping address required for reorder is incomplete |
| `manual_item_match_failed` | Claimed line items could not be matched to the order |
| `manual_shopify_error` | Shop platform returned an error during refund/reorder |
| `manual_already_processed` | Another claim on this order was already auto-resolved |
A claim whose **claimed value** cannot be calculated is not stamped with an
outcome at all — a value condition simply does not match, so the rule is
skipped and the claim falls through to manual handling like any other
non-match.
Karla also treats an order as **already processed** once any claim on that
order received an automated outcome — preventing duplicate refunds or
replacements from repeat submissions.
These gates are not configurable in the portal today; they protect your shop
regardless of how permissive your rules are.
## Customer resolution preference
What the customer selects in Resolve (when you expose the choice) drives the
outcome of a matched **Automate** rule — **Refund** and **Reorder** rules
ignore it:
| Preference | Automated action |
| ------------------ | ---------------------------------------------------------------------- |
| `refund` | Issue a refund in your shop |
| `reorder` | Create a replacement order |
| `keep_with_reward` | Available as a rule condition; use when you offer keep-item incentives |
The options customers can pick from are configurable under
**Resolve → Features → Resolution options** in the portal — refund and
reorder are enabled by default; enable keep with reward there to offer it.
You control whether customers see the preference picker per flow in
[Flows and customization](./flows-and-customization). Hiding the picker does
not remove the preference from the claim: Resolve submits `refund` when the
picker is hidden (or the sole configured option when only one is enabled),
and a matched **Automate** rule acts on that default like any other
preference. If you hide the picker, **Automate** simply resolves to that
default for every widget claim — prefer the explicit **Refund** or
**Reorder** action there so the intent is visible in your rule set.
## API access
Claim automation settings are available programmatically for headless or
multi-shop setups:
```bash title="GET /v1/shops/{slug}/settings/triggers/claim-resolution"
curl -X GET "https://api.gokarla.io/v1/shops/{slug}/settings/triggers/claim-resolution" \
-H "Authorization: Bearer YOUR_API_KEY"
```
```bash title="PATCH /v1/shops/{slug}/settings/triggers/claim-resolution"
curl -X PATCH "https://api.gokarla.io/v1/shops/{slug}/settings/triggers/claim-resolution" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": true,
"notify_mode": "notify",
"rules": [
{
"action": "automate",
"conditions": [
{ "field": "claim_reason", "op": "equals", "value": "missing_product" },
{ "field": "claimed_value", "op": "<=", "value": 75 }
]
}
]
}'
```
A `PATCH` replaces the full `rules` array when you include it. Omit fields you
want to leave unchanged. `action` accepts `refund`, `reorder`, `automate`, or
`manual`, and every rule must carry at least one condition.
Operators over the API are `equals`, `in`, `<=`, `<`, `>`, and `>=`. The `in`
operator takes a **JSON list**, not a comma-separated string:
```json title="Matching several claim reasons"
{
"field": "claim_reason",
"op": "in",
"value": ["missing_product", "wrong_product"]
}
```
Numeric fields (`claimed_value`, `claimed_quantity`) take a number and reject
`in`; categorical fields (`claim_reason`, `resolution_preference`,
`shipment_status`) reject the numeric comparison operators.
## Troubleshooting
**Automation never runs**
- Confirm **Enable claim automation** is on.
- Confirm at least one **Automate** rule exists and its conditions match real
claim data (check reason codes and claimed value).
- Confirm the shop is connected to **Shopify** — refunds and replacements are
executed there, and shops without Shopify access fall back to manual.
- Confirm no rule targets the deprecated `partial_damage` reason; use `damage`.
**Rule matches but claim stays manual**
- Check the claim's **resolution outcome** in the API — a safety gate may have
blocked execution (out of stock, already processed, etc.).
- For **Automate** rules, confirm the claim carries a `refund` or `reorder`
resolution preference — claims from other sources may have none, and
`keep_with_reward` has no automated path. Switch the rule to an explicit
**Refund** or **Reorder** action if the outcome should not depend on it.
**Agents not notified after automation**
- Set **Notification mode** to **Notify** if you expect helpdesk tickets for
automated outcomes.
- Confirm your helpdesk integration is connected and enabled.
**Wrong priority between rules**
- Remember **first match wins**. Move stricter or higher-priority rules above
broader catch-all rules.
## Where to next
- [Integration and automation](./integration-and-automation) — helpdesk routing
and custom transformations beyond claim automation.
- [Shop connection](./shop-connection) — what Resolve needs from your shop.
- [Data processing](./data-processing) — the claim payload rules evaluate.
- [Flows and customization](./flows-and-customization) — customer-facing
resolution preference and flow toggles.
- [Helpdesk integrations](./integrations/overview) — tickets for manual claims
and notify-mode outcomes.
- [Portal → Resolve](/docs/guides/portal/resolve) — claims analytics and the
Claims table.
---
## Returns
Source: https://gokarla.io/docs/guides/resolve/returns
# Returns
The **Return** flow in Resolve handles wrong-size, changed-mind, and
doesn't-fit cases — and Karla can handle the return label for you. When a
customer walks through the flow, Karla generates the label and hands it to
them right there in the browser: no support ticket, no back-and-forth, no
manually emailing PDFs.
If you run returns in a third-party tool instead, Resolve can
[hand the customer off to your returns portal](#handoff-to-your-returns-portal)
at the right moment — both models are covered below.
## Native returns
**Native returns** keep the full return journey inside Resolve — on-brand,
end to end, without sending the customer elsewhere.
Customers select items, choose a return reason, and confirm details inside
Resolve; Karla then creates the return label on the spot and presents it in
the same flow. Every input is captured as structured claim data, so you get
the same analytics and intelligence as your other Resolve flows (reason
breakdowns, product-level patterns, geographic trends).
### What your customer sees
Once the customer reaches the label step, the label is generated
automatically — no extra clicks, no waiting for an agent:
- **Return label in the browser** — a PDF label to download and print,
alongside the return tracking number with a one-tap copy button.
- **QR code for drop-off** — DHL national returns also come with a QR code,
rendered directly in the flow. The customer has it scanned at the parcel
shop; nothing to print.
- **QR code by email** — when the order has an email address, Karla also
emails the QR code to the customer as a PNG attachment, so it's still at
hand if they only get to the drop-off point days later.
A summary of the items being returned and the selected reason is shown next
to the label, so the customer can double-check before handing over the
parcel.
:::tip
The return is registered as a shipment on the order the moment the label is
created — you can follow the parcel back to your warehouse the same way you
track outbound deliveries.
:::
### Setting it up
Return providers are configured in the
[Merchant Portal](https://portal.gokarla.io) under **Resolve → Labels**:
- **DHL Parcel DE** — the provider that generates native return labels today.
It uses your own DHL contract, so returns ship to the receiver ID registered
with your DHL Parcel DE credentials (connected under
**Settings → Integrations → DHL**).
- **Karla Labels** — Karla handles the carrier relationship and ships returns
to a return address you configure. The toggle and address fields are already
in the portal, but Karla Labels is not generating labels yet.
[Talk to us](https://calendly.com/frederik-s/25min) if you need return labels
beyond DHL.
:::note
Once DHL is enabled, **every** native return label is created through it,
regardless of which carrier delivered the original order — merchants who ship
outbound with one carrier and take returns via DHL are the normal case.
:::
### Good to know
- **One return label per order.** If a return label already exists for an
order, a second request is refused rather than billing you for a duplicate.
- **EU shipping addresses.** Native return labels are available for orders
with an EU shipping address — returns from outside the EU need a customs
declaration, which Karla does not generate yet.
- **No provider configured?** The Return flow keeps working: the claim still
reaches you as structured data, but instead of a label the customer sees a
notice that one can't be created for the order and is asked to contact your
support team. Shops in this state typically use the handoff below.
[Talk to us](https://calendly.com/frederik-s/25min)
to discuss how native returns fit your operation.
The customer-facing steps that lead up to the label are configured with the
rest of the Return flow.
## Handoff to your returns portal
If you run returns in a third-party tool (Loop, ReturnGO, your own portal,
or anything else), Resolve can transfer the customer there at the right
moment in the flow — after they've picked items and given a reason, or as
soon as they choose **Return**, depending on how you configure the steps.
The handoff is seamless for the customer: Resolve shows a short transition
screen, then opens your returns URL in a new tab. You can pass order context
along in the URL so your tool can recognize the customer immediately.
### What you can pass along
Configure your destination URL with placeholders; Karla fills them in when
the customer is redirected:
| Placeholder | Typical use |
| -------------------- | ------------------------------------------------------- |
| `{orderNumber}` | Pre-fill the order lookup on your returns site |
| `{orderName}` | Shop-specific order reference (e.g. `#1234`) |
| `{email}` | Pre-populate the customer email field |
| `{zipCode}` | Match against your existing order verification |
| `{externalId}` | Your shop system's order ID |
| `{claimReason}` | The return reason the customer selected in Resolve |
| `{selectedItemSkus}` | Comma-separated SKUs for the items they chose to return |
| `{flowType}` | Always `return` for this flow |
A typical setup might look like:
```jsx title="Example returns handoff URL"
https://returns.yourbrand.com/start?order={orderNumber}&email={email}&reason={claimReason}
```
The customer lands on your tool with their order and email already in
place — they can start the return immediately instead of hunting for order
details again.
Configure the handoff URL in the
[Merchant Portal](https://portal.gokarla.io) as part of your Return flow;
see [Flows and customization](./flows-and-customization) for step-level
options.
## Where to next
- [Flows and customization](./flows-and-customization) — configure the
Return flow, handoff timing, and step order.
- [Data processing](./data-processing) — what claim data looks like after
submission.
- [Integration and automation](./integration-and-automation) — route
return claims to your helpdesk or automation layer.
- [Portal → Resolve](/docs/guides/portal/resolve) — claims analytics and
the Claims table.
---
## Helpdesk integrations
Source: https://gokarla.io/docs/guides/resolve/integrations/overview
# Helpdesk integrations
When a customer submits a Resolve claim, Karla opens a fully populated ticket
in your helpdesk — photos, affected items, order context, and resolution
preference included. No copy-pasting, no JSON dumps.
## Two ways to connect
Connect Zendesk, Gorgias, Dixa, Front, Kustomer, or Intercom directly in the
[Karla portal](https://portal.gokarla.io). Karla authenticates with your
instance and creates tickets with the right fields, attachments, and
customer threading. No native helpdesk? An [email fallback](./email) sends
claims to your support inbox.
Use Karla webhooks to push claim events to any helpdesk, workflow tool, or
middleware. You receive the same structured payload described in [Data
processing](../data-processing) and map it to tickets yourself — or let a
connector like Zapier or Make handle the translation.
:::tip Which path should I pick?
Use a **native integration** when Karla supports your helpdesk out of the box —
setup takes a few minutes in the portal and ticket formatting is handled for
you. Use **webhooks** when you run a custom stack, need a non-standard ticket
shape, or want to fan out the same claim to multiple destinations.
:::
## Prerequisites
Before connecting a helpdesk, make sure:
- Your **shop is connected** to Karla — Resolve needs order, shipment, and
customer context. See [Shop connection](../shop-connection).
- **Resolve is enabled** on your Karla package. Contact your account manager
if you do not see Resolve settings in the portal.
- You understand the **claim payload** — what fields Karla sends when a
customer submits. See [Data processing](../data-processing) and
[Claim events](/docs/platform/events/claims).
## Supported helpdesks
| Helpdesk | Native integration | Setup guide |
| -------- | ------------------ | ------------------------ |
| Zendesk | Yes | [Zendesk →](./zendesk) |
| Gorgias | Yes | [Gorgias →](./gorgias) |
| Dixa | Yes | [Dixa →](./dixa) |
| Front | Yes | [Front →](./front) |
| Kustomer | Yes | [Kustomer →](./kustomer) |
| Intercom | Yes | [Intercom →](./intercom) |
| Email | Fallback | [Email →](./email) |
| Other | Via webhooks | [Webhooks →](./webhooks) |
Karla maps each Resolve flow (defective, return, not received, etc.) to the
right ticket type and attaches evidence automatically. For routing rules,
auto-refunds, and custom transformations beyond ticket creation, see
[Integration and automation](../integration-and-automation).
## Ticket templates
For native helpdesks (Zendesk, Gorgias, Dixa, Front, Kustomer, Intercom), Karla ships sensible default
ticket wording, but you can override the **subject**, **body**, **tags**, and
**attachments** per claim reason directly in the portal. Leave any field on
"Use default" to keep Karla's shipped wording.
Subject and body support these placeholder variables — a missing value renders
as an empty string:
| Variable | Renders |
| ----------------------------- | -------------------------------------------------------------------------------------------- |
| `{full_name}` | Shipping-address recipient name |
| `{email}` | Customer email |
| `{order_name}` | Order name (e.g. `#1001`) |
| `{order_number}` | Order number |
| `{external_id}` | Your shop system's order ID |
| `{tracking_id}` | Shipment tracking number |
| `{tracking_url}` | Shipment tracking link |
| `{country}` | Shipping-address country code (e.g. `DE`) |
| `{selected_items}` | Claimed items, with SKU and quantity |
| `{description}` | Customer's claim description |
| `{resolution_preference}` | Requested resolution (refund / reorder) |
| `{reason}` | Claim reason |
| `{step_inputs}` | Customer's Resolve answers, as question/answer pairs |
| `{dropoff_permission}` | Whether the customer allows drop-off (`Ja` / `Nein`) |
| `{automation_failure_reason}` | Why an automated refund or reorder fell back to a manual ticket — blank unless that happened |
## What Karla sends to your helpdesk
Regardless of integration type, your team receives a ticket built from the
same structured claim:
- **Issue type and reason** — which Resolve flow the customer entered and the
specific reason they selected.
- **Affected items** — SKUs, titles, quantities.
- **Customer preference** — refund, replacement, or the options you exposed.
- **Evidence** — photos, signatures, free-text descriptions.
- **Order context** — order number, shipment phase, carrier, delivery address.
For the full payload shape, see [Data processing](../data-processing).
## Where to next
- [Zendesk](./zendesk) — self-service setup with API token authentication.
- [Gorgias](./gorgias) — self-service setup with API key authentication and
optional Help Center embed.
- [Dixa](./dixa) — self-service setup with bearer-token authentication.
- [Front](./front) — self-service setup with bearer-token authentication and
claim import into a shared inbox.
- [Kustomer](./kustomer) — self-service setup with bearer-token authentication
and conversation + note creation.
- [Intercom](./intercom) — self-service setup with bearer-token authentication
and ticket type configuration.
- [Email](./email) — fallback that emails claims to your support inbox.
- [Webhooks](./webhooks) — connect any helpdesk via claim event webhooks.
- [Integration and automation](../integration-and-automation) — automated
refunds, conditional routing, and custom outputs.
- [Integrate in your shop](../integrate-in-your-shop) — embed Resolve on your
storefront.
---
## Zendesk
Source: https://gokarla.io/docs/guides/resolve/integrations/zendesk
# Zendesk
:::info
The Zendesk integration creates a structured ticket in your Zendesk instance
whenever a customer submits a Resolve claim. Photos, affected items, order
context, and the customer's resolution preference are attached automatically.
:::
## What you need
Before you start, gather:
- **Zendesk admin access** — to create an API token.
- **Your Zendesk subdomain** — the label in front of `.zendesk.com`, e.g.
`yourbrand` in `https://yourbrand.zendesk.com`. You enter just the subdomain
in the portal; Karla appends `.zendesk.com`.
- **An agent email address** — the Zendesk user Karla will authenticate as.
Must belong to an agent or admin with permission to create tickets.
- **A Zendesk API token** — used together with the agent email for Basic
authentication.
Karla uses **Basic authentication** with the combination `{email}/token:{api_token}`.
This is Zendesk's standard API auth pattern — not your account password.
## Steps
### 1. Enable API token access in Zendesk
In Zendesk, open **Admin Center** and navigate to **Apps and integrations →
Zendesk API**.
On the **Settings** tab, make sure **Token Access** is enabled.
### 2. Create an API token
Still under **Zendesk API**, open the **API tokens** tab and click **Add API
token**.
Name it something recognizable — e.g. `Karla Resolve Integration` — and copy
the token immediately. Zendesk only shows it once.
:::warning
Treat the API token like a password. Do not share it in email or chat — enter
it only in the Karla portal.
:::
### 3. Note your Zendesk subdomain
Your subdomain is the label in front of `.zendesk.com`:
```text title="Zendesk subdomain"
yourbrand (from https://yourbrand.zendesk.com)
```
Enter only the subdomain (`yourbrand`) in the portal — not the full URL. Karla
appends `.zendesk.com` and uses it to route API calls to the correct account.
### 4. Connect Zendesk in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Zendesk**.
Enter your credentials under **API Configuration**:
| Field | Value |
| ----------------- | -------------------------------------------------- |
| **Account Email** | The agent email address Karla will authenticate as |
| **API Key** | The Zendesk API token you created in step 2 |
Save the credentials, then under **Integration Settings** enter your
**Subdomain** (`yourbrand`) and save it. Karla validates against your Zendesk
instance using Basic authentication before storing.
Once a subdomain is saved, toggle the integration on. New Resolve claims will
create tickets in Zendesk automatically.
:::note
If you do not see Zendesk under **Settings → Integrations**, contact your
account manager — the integration may need to be enabled for your shop first.
:::
### 5. Optional settings
A few extra settings live alongside the connection, all optional:
- **Notify Customer on Claim** — on by default. When on, the customer is copied
on the claim ticket; turn it off to keep tickets internal. (Your own Zendesk
autoreply triggers are separate and unaffected.)
- **Brand ID** — for Zendesk instances serving multiple brands, the numeric
brand new tickets are assigned to. Leave empty to use your default brand.
- **Carrier affidavit** — saving a postal **sender address** (plus optional
**type of goods** and **main carrier**) attaches a carrier affidavit PDF to
investigation (not-received) tickets, ready for carrier disputes. Clearing
the sender address removes it.
- **Ticket templates** — customize the subject, body, tags, and attachments
per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Zendesk
When a customer submits a Resolve claim, Karla opens a Zendesk ticket with:
- **Subject and description** mapped from the claim reason and customer notes.
- **Requester** set to the customer email from the order.
- **Custom fields and tags** reflecting the Resolve flow type, resolution
preference, and shipment phase (configured per shop).
- **Attachments** — claim photos and signatures uploaded as ticket attachments.
- **Order and shipment context** in the ticket body — order number, carrier,
tracking number, affected line items.
Your agents see a complete ticket without looking up the order elsewhere.
## Troubleshooting
**Authentication failed after saving**
- Confirm the email belongs to an active agent or admin in Zendesk.
- Confirm the API token was copied in full — no leading or trailing spaces.
- Confirm Token Access is enabled in Zendesk Admin Center.
- Use the `{email}/token:{api_token}` format — the literal word `token` between
the email and the API token is required by Zendesk.
**Tickets not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
- Check that the agent email has permission to create tickets in Zendesk.
**Wrong Zendesk instance**
- Double-check the **Subdomain** field is just the label (`yourbrand`) — no
`https://`, no `.zendesk.com`, no trailing path.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Gorgias](./gorgias) — native Gorgias integration setup.
- [Dixa](./dixa) — native Dixa integration setup.
- [Kustomer](./kustomer) — native Kustomer integration setup.
- [Intercom](./intercom) — native Intercom integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integration and automation](../integration-and-automation) — auto-refunds,
routing rules, and custom transformations.
---
## Gorgias
Source: https://gokarla.io/docs/guides/resolve/integrations/gorgias
# Gorgias
:::info
The Gorgias integration creates a structured ticket in your Gorgias account
whenever a customer submits a Resolve claim. Photos, affected items, order
context, and the customer's resolution preference are attached automatically.
You can also embed a Resolve entry point directly in your Gorgias Help Center
so customers start a claim from your support site.
:::
## What you need
Before you start, gather:
- **Gorgias admin access** — to create an API key.
- **Your Gorgias subdomain** — the label in front of `.gorgias.com`, e.g.
`yourbrand` in `https://yourbrand.gorgias.com`. You enter just the subdomain
in the portal; Karla appends `.gorgias.com`.
- **An agent email address** — the Gorgias user Karla will authenticate as.
Must belong to an agent or admin with permission to create tickets.
- **A Gorgias API key** — created under **Settings → REST API**.
Karla uses **Basic authentication** with your email as the username and the
API key as the password (`email:api_key`). This is Gorgias's standard REST
API auth pattern — not your account password.
## Connect Gorgias for ticket creation
### 1. Create an API key in Gorgias
In Gorgias, open **Settings → REST API** and click **Create API key**.
Name it something recognizable — e.g. `Karla Resolve Integration` — and copy
the key immediately.
:::warning
Treat the API key like a password. Do not share it in email or chat — enter
it only in the Karla portal.
:::
The user associated with the API key must have permission to create tickets
and access customer records. Admin or full agent roles work best.
### 2. Note your Gorgias subdomain
Your subdomain is the label in front of `.gorgias.com`:
```text title="Gorgias subdomain"
yourbrand (from https://yourbrand.gorgias.com)
```
Enter only the subdomain (`yourbrand`) in the portal — not the full URL. Karla
appends `.gorgias.com` and uses it to route API calls to the correct account.
### 3. Connect Gorgias in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Gorgias**.
Enter your credentials under **API Configuration**:
| Field | Value |
| ----------------- | -------------------------------------------------- |
| **Account Email** | The agent email address Karla will authenticate as |
| **API Key** | The key you created in step 1 |
Save the credentials, then under **Integration Settings** enter your
**Subdomain** (`yourbrand`) and save it. Karla validates against your Gorgias
account using Basic authentication before storing.
Once a subdomain is saved, toggle the integration on. New Resolve claims will
create tickets in Gorgias automatically.
:::note
If you do not see Gorgias under **Settings → Integrations**, contact your
account manager — the integration may need to be enabled for your shop first.
:::
### 4. Optional settings
Six optional settings live alongside the connection, all under **Integration
Settings**:
- **Send Claims as Email Channel** — creates the claim ticket on Gorgias's
`email` channel instead of `api`. The ticket is still created through the same
authenticated API call; only the channel changes, so your Gorgias rules and
macros treat it as an email.
- **Send Auto-Reply to Customer** — automatically replies to the customer once
the claim ticket is created. The reply only goes out when this is on _and_ the
message below is not empty.
- **Auto-Reply Message** — the reply text itself. Use the `{order_name}`
variable to include the order number.
- **Reply-From Address** — the connected Gorgias email address the auto-reply is
sent from, e.g. your support inbox.
:::warning
The auto-reply is **silently skipped** if no Reply-From Address is saved. Your
API auth email is not a sendable channel, so Gorgias rejects it — set a real
sendable address here or the reply never leaves.
:::
- **Carrier affidavit** — saving a postal **Sender Address** (plus optional
**Type of Goods** and **Main Carrier**) attaches a carrier affidavit PDF to
investigation (not-received) tickets, ready for carrier disputes. Clearing
the sender address removes it.
- **Ticket templates** — customize the subject, body, tags, and attachments
per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Gorgias
When a customer submits a Resolve claim, Karla opens a Gorgias ticket with:
- **Subject and message body** mapped from the claim reason and customer notes.
- **Customer** matched or created from the order email.
- **Tags and custom fields** reflecting the Resolve flow type, resolution
preference, and shipment phase (configured per shop).
- **Attachments** — claim photos and signatures uploaded to the ticket.
- **Order and shipment context** in the ticket body — order number, carrier,
tracking number, affected line items.
Your agents see a complete ticket without looking up the order elsewhere.
## Embed Resolve in your Help Center (optional)
In addition to ticket creation, you can surface a Resolve entry point inside
your Gorgias Help Center. Customers click a branded tile and are taken to
the Resolve flow for your shop — pre-localized based on the Help Center
language.
Supported Help Center languages: English, German, French, Spanish, Italian,
Dutch, Danish, and Polish.
### 1. Share your Help Center URLs with Karla
The Help Center embed is activated per domain. Send Karla the URLs where you
want the Resolve tile to appear — for example your Help Center home page,
contact page, or return-policy articles.
Karla whitelists those URLs before the widget goes live.
### 2. Add the Gorgias SDK to your Help Center
Karla provides a script tag for your shop. Add it to your Gorgias Help
Center custom code (typically under **Settings → Help Center → Advanced** or
your theme's custom HTML/JS section):
```html
```
Replace `my-shop-slug` with your Karla shop slug (find it in the
[portal](https://portal.gokarla.io/) under your shop profile).
When a customer clicks the tile, they are redirected to your Resolve flow at
`https://app.gokarla.io/resolve/{shop-slug}/finder`, with the language taken
from the Help Center URL.
:::tip Help Center + ticket integration together
Most merchants use both: the Help Center tile drives customers into Resolve
self-service, and the native integration creates structured Gorgias tickets
when they submit a claim. They complement each other — you do not need to
pick one or the other.
:::
## Troubleshooting
**Authentication failed after saving**
- Confirm the email belongs to an active agent or admin in Gorgias.
- Confirm the API key was copied in full — no leading or trailing spaces.
- Confirm the key was created under **Settings → REST API**, not expired or
revoked.
- Basic auth uses `email:api_key` — your account password will not work.
**Tickets not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
- Check that the agent email has permission to create tickets in Gorgias.
**Wrong Gorgias account**
- Double-check the **Subdomain** field is just the label (`yourbrand`) — no
`https://`, no `.gorgias.com`, no trailing path.
**Help Center tile not showing**
- Confirm Karla has whitelisted your Help Center URLs.
- Confirm the script tag includes the correct `data-shop-slug`.
- Confirm the SDK script is present in your Help Center custom code and the
page has been published.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Zendesk](./zendesk) — native Zendesk integration setup.
- [Dixa](./dixa) — native Dixa integration setup.
- [Kustomer](./kustomer) — native Kustomer integration setup.
- [Intercom](./intercom) — native Intercom integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integrate in your shop](../integrate-in-your-shop) — embed Resolve on your
storefront via the Browser SDK.
---
## Dixa
Source: https://gokarla.io/docs/guides/resolve/integrations/dixa
# Dixa
:::info
The Dixa integration creates a structured conversation in your Dixa account
whenever a customer submits a Resolve claim. Photos, affected items, order
context, and the customer's resolution preference are attached automatically.
:::
## What you need
Before you start, gather:
- **Dixa admin access** — to create an API token.
- **A Dixa API token** — created under **Settings → Integrations → API tokens**.
Dixa uses **bearer-token authentication**, so unlike Zendesk or Gorgias there
is no account email or subdomain to provide.
- **An email integration ID** — the Dixa email contact endpoint new
conversations belong to, e.g. `support@acme.dixa.io`. Find it under your Dixa
contact endpoints. This is required before you can enable the integration.
- **A default agent ID** (optional) — the UUID of the agent new conversations
should be assigned to. Leave it empty to let Dixa route conversations through
its own queues.
Karla authenticates with your API token only — not your Dixa account password.
## Connect Dixa for conversation creation
### 1. Create an API token in Dixa
In Dixa, open **Settings → Integrations → API tokens** and create a token with
conversation access.
Name it something recognizable — e.g. `Karla Resolve Integration` — and copy
the token immediately.
:::warning
Treat the API token like a password. Do not share it in email or chat — enter
it only in the Karla portal.
:::
### 2. Note your email contact endpoint
Dixa creates email conversations against a **contact endpoint** — the mailbox
address new conversations belong to. You enter this value as the **Email
Integration ID** in the Karla portal.
Find it in Dixa under your contact endpoints (email channels), or list them via
the Dixa API (`GET /v1/contact-endpoints`). The value looks like:
```text title="Email integration ID"
support@acme.dixa.io
```
Enter the full contact-endpoint address — not a display name or queue label.
### 3. Connect Dixa in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Dixa**.
Under **API Configuration**, paste your **API Token** and save it. Karla stores
it in a secret manager and shows only a masked preview afterward.
### 4. Configure the email integration
Once the token is saved, the **Integration Settings** unlock:
| Field | Value |
| ------------------------ | ------------------------------------------------------ |
| **Email Integration ID** | The Dixa contact endpoint, e.g. `support@acme.dixa.io` |
| **Default Agent ID** | Optional agent UUID to assign new conversations to |
Save the email integration ID, then toggle the integration on. New Resolve
claims will create tagged conversations in Dixa automatically.
:::note
The integration cannot be enabled until an email integration ID is saved — Dixa
creates conversations against a mailbox, so the endpoint is required.
:::
:::note
If you do not see Dixa under **Settings → Integrations**, contact your account
manager — the integration may need to be enabled for your shop first.
:::
### 5. Optional settings
One optional setting lives alongside the connection:
- **Ticket templates** — customize the subject, body, tags, and attachments
per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Dixa
When a customer submits a Resolve claim, Karla opens a Dixa conversation with:
- **Subject and message** mapped from the claim reason and customer notes.
- **Customer** matched or created from the order email.
- **Tags** reflecting the Resolve flow type, resolution preference, and
shipment phase (configured per shop).
- **Attachments** — claim photos and signatures uploaded to the conversation.
- **Order and shipment context** in the conversation — order number, carrier,
tracking number, affected line items.
Your agents see a complete conversation without looking up the order elsewhere.
## Troubleshooting
**Cannot enable the integration**
- Save an **Email Integration ID** first — the toggle stays disabled until one
is stored.
**Conversations not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm the email integration ID matches a real Dixa contact endpoint.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
**Authentication failed after saving**
- Confirm the API token was copied in full — no leading or trailing spaces.
- Confirm the token was created with conversation access and is not expired or
revoked.
**Wrong contact endpoint**
- Double-check the **Email Integration ID** is the full mailbox address (e.g.
`support@acme.dixa.io`) — not a queue name, agent email, or internal UUID.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Zendesk](./zendesk) — native Zendesk integration setup.
- [Gorgias](./gorgias) — native Gorgias integration setup.
- [Kustomer](./kustomer) — native Kustomer integration setup.
- [Intercom](./intercom) — native Intercom integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integration and automation](../integration-and-automation) — auto-refunds,
routing rules, and custom transformations.
- [Integrate in your shop](../integrate-in-your-shop) — embed Resolve on your
storefront via the Browser SDK.
---
## Front
Source: https://gokarla.io/docs/guides/resolve/integrations/front
# Front
:::info
The Front integration imports a claim into your Front inbox as an inbound email
conversation whenever a customer submits a Resolve claim. Photos, affected
items, order context, and the carrier affidavit PDF are attached automatically,
and Karla can optionally reply to the customer in the same conversation.
:::
## What you need
Before you start, gather:
- **Front admin access** — to create an API token.
- **A Front API token** — created under **Settings → Developers → API tokens**.
Front uses **bearer-token authentication**, so unlike Zendesk or Gorgias there
is no account email or subdomain to provide.
- **An inbox ID** — the Front inbox claims are imported into, e.g. `inb_123`.
This is required before you can enable the integration.
- **A recipient email** — your support inbox address that imported claim
messages are addressed to. This is also required before enabling.
- **A reply channel ID and author ID** (optional) — only needed if you turn on
the automatic acknowledgement reply.
Karla authenticates with your API token only — not your Front account password.
## Connect Front for claim import
### 1. Create an API token in Front
In Front, open **Settings → Developers → API tokens** and create a token with
access to your inboxes and conversations.
Name it something recognizable — e.g. `Karla Resolve Integration` — and copy
the token immediately.
:::warning
Treat the API token like a password. Do not share it in email or chat — enter
it only in the Karla portal.
:::
### 2. Note your inbox ID
Front imports claim messages into a specific **inbox**. Open
**Settings → Inboxes** in Front and select the inbox you want claims to land in.
The ID appears in the URL and starts with `inb_`:
```text title="Inbox ID"
inb_1a2b3c
```
Enter the inbox ID — not the inbox display name.
### 3. Connect Front in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Front**.
Under **API Configuration**, paste your **API Token** and save it. Karla stores
it in a secret manager and shows only a masked preview afterward.
### 4. Configure the inbox
Once the token is saved, the **Integration Settings** unlock:
| Field | Value |
| ------------------- | --------------------------------------------------------- |
| **Inbox ID** | The Front inbox claims are imported into, e.g. `inb_123` |
| **Recipient Email** | Your support address the imported message is addressed to |
Save both values, then toggle the integration on. New Resolve claims will be
imported into Front automatically.
:::note
The integration cannot be enabled until **both** an inbox ID and a recipient
email are saved — Front needs an inbox to import into and an address to import
the message against.
:::
:::note
If you do not see Front under **Settings → Integrations**, contact your account
manager — the integration may need to be enabled for your shop first.
:::
### 5. Optional: automatic acknowledgement reply
Turn on **Send Auto Reply** to have Karla reply to the customer in the same
Front conversation as soon as their claim is imported. When enabled, four more
fields appear:
| Field | Value |
| ---------------------- | -------------------------------------------------- |
| **Auto-Reply Subject** | Subject line used for the reply email |
| **Auto-Reply Message** | The message body sent to the customer |
| **Reply Channel ID** | The Front channel the reply is sent from (`cha_…`) |
| **Reply Author ID** | The Front teammate the reply is sent as (`tea_…`) |
The reply is only sent when the toggle is on **and** a message is set — leaving
the message empty skips the reply. Enable **Archive After Reply** to archive the
conversation once the acknowledgement goes out.
### 6. Other optional settings
Alongside the connection:
- **Sender Address** — your postal sender line for the carrier affidavit PDF.
Saving an address attaches the affidavit to investigation (not received)
tickets; clearing it removes the affidavit.
- **Type of Goods** — what your parcels contain, printed as the content
("Inhalt") line on the affidavit.
- **Main Carrier** — which carrier's form is used for the affidavit. Leave it on
_Automatic_ to route by the shipment's own carrier.
- **Ticket templates** — customize the subject, body, tags, and attachments
per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Front
When a customer submits a Resolve claim, Karla imports a conversation with:
- **Subject and message** mapped from the claim reason and customer notes.
- **Customer** identified by the order email, so the conversation threads with
their existing history.
- **Attachments** — claim photos and, when configured, the carrier affidavit
PDF.
- **Order and shipment context** in the message body — order number, carrier,
tracking number, affected line items.
- **An optional agent reply** acknowledging the claim, when auto reply is on.
Your agents see a complete conversation without looking up the order elsewhere.
## Troubleshooting
**Cannot enable the integration**
- Save both an **Inbox ID** and a **Recipient Email** — the toggle stays
disabled until both are stored.
**Conversations not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm the inbox ID matches a real Front inbox and starts with `inb_`.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
**Authentication failed after saving**
- Confirm the API token was copied in full — no leading or trailing spaces.
- Confirm the token has inbox and conversation access and is not expired or
revoked.
**Auto reply not sent**
- Confirm **Send Auto Reply** is on _and_ an auto-reply message is saved — an
empty message skips the reply.
- Confirm the **Reply Channel ID** (`cha_…`) and **Reply Author ID** (`tea_…`)
are set and belong to the same Front account.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Zendesk](./zendesk) — native Zendesk integration setup.
- [Gorgias](./gorgias) — native Gorgias integration setup.
- [Dixa](./dixa) — native Dixa integration setup.
- [Kustomer](./kustomer) — native Kustomer integration setup.
- [Intercom](./intercom) — native Intercom integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integration and automation](../integration-and-automation) — auto-refunds,
routing rules, and custom transformations.
- [Integrate in your shop](../integrate-in-your-shop) — embed Resolve on your
storefront via the Browser SDK.
---
## Kustomer
Source: https://gokarla.io/docs/guides/resolve/integrations/kustomer
# Kustomer
:::info
The Kustomer integration creates a structured conversation in your Kustomer
account whenever a customer submits a Resolve claim. Karla matches or creates
the customer, opens a conversation, and attaches the full claim — photos,
affected items, order context, and resolution preference — as an internal note
your agents can act on immediately.
:::
## What you need
Before you start, gather:
- **Kustomer admin access** — to create an API key with the right permissions.
- **Your Kustomer organization name** — the label in your Kustomer app URL, e.g.
`yourbrand` in `https://yourbrand.kustomerapp.com`. Karla uses it to route
API calls to `https://yourbrand.api.kustomerapp.com`.
- **A Kustomer API key** — created under **Settings → Security → API Keys**.
The key needs permission to read and create customers, create conversations,
and create notes.
Karla authenticates with **bearer-token authentication**
(`Authorization: Bearer {api_key}`) — not your Kustomer account password.
## Connect Kustomer for conversation creation
### 1. Create an API key in Kustomer
In Kustomer, open **Settings → Security → API Keys** and create a key with
access to customers, conversations, and notes.
Name it something recognizable — e.g. `Karla Resolve Integration` — and copy
the key immediately.
:::warning
Treat the API key like a password. Do not share it in email or chat — enter
it only in the Karla portal.
:::
The key needs at least these permission sets (or their legacy equivalents):
| Permission | Used for |
| ------------------- | ----------------------------------------------- |
| Customer read | Look up existing customers by email |
| Customer create | Create a customer when none exists |
| Conversation create | Open a new conversation for the customer |
| Note create | Attach the structured claim as an internal note |
### 2. Note your organization name
Your organization name is the label in your Kustomer app URL:
```text title="Kustomer organization name"
yourbrand (from https://yourbrand.kustomerapp.com)
```
Enter only the organization name (`yourbrand`) in the portal — not the full
URL. Karla appends `.api.kustomerapp.com` and uses it to route API calls to
the correct Kustomer workspace.
### 3. Connect Kustomer in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Kustomer**.
Enter your credentials under **API Configuration**:
| Field | Value |
| ---------------- | --------------------------------------------- |
| **API Key** | The key you created in step 1 |
| **Organization** | Your Kustomer organization name (`yourbrand`) |
Save the credentials. Karla validates against your Kustomer workspace using
bearer authentication before storing.
Once credentials are saved, toggle the integration on. New Resolve claims will
create conversations in Kustomer automatically.
:::note
If you do not see Kustomer under **Settings → Integrations**, contact your
account manager — the integration may need to be enabled for your shop first.
:::
### 4. Optional settings
A few extra settings live alongside the connection, all optional:
- **Default team ID** — for Kustomer workspaces using teams, the team new
conversations should be assigned to. Leave empty to let Kustomer route through
its own queues.
- **Carrier affidavit** — saving a postal **sender address** (plus optional
**type of goods** and **main carrier**) attaches a carrier affidavit PDF to
investigation (not-received) conversations, ready for carrier disputes.
Clearing the sender address removes it.
- **Ticket templates** — customize the conversation name, note body, tags, and
attachments per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Kustomer
When a customer submits a Resolve claim, Karla:
1. **Matches or creates the customer** — looks up the order email in Kustomer
(`GET /v1/customers/email={email}`). If no match exists, Karla creates a new
customer record with the shipping name and email from the order.
2. **Opens a conversation** — creates a new conversation on that customer
(`POST /v1/customers/{id}/conversations`) with tags reflecting the Resolve
flow type, resolution preference, and shipment phase.
3. **Attaches the claim as an internal note** — posts the structured claim
details to the conversation (`POST /v1/notes`) so agents see everything in
one place without a public customer-facing message.
The note includes:
- **Subject and body** mapped from the claim reason and customer notes.
- **Tags** reflecting the Resolve flow type, resolution preference, and
shipment phase (configured per shop).
- **Attachments** — claim photos and signatures linked to the conversation.
- **Order and shipment context** — order number, carrier, tracking number,
affected line items.
Your agents see a complete conversation with an internal note — no copy-pasting,
no looking up the order elsewhere.
## Troubleshooting
**Authentication failed after saving**
- Confirm the API key was copied in full — no leading or trailing spaces.
- Confirm the key was created under **Settings → Security → API Keys** and is
not expired or revoked.
- Confirm the **Organization** field matches your Kustomer workspace name
exactly — the label from `https://{org}.kustomerapp.com`, not the full URL.
**Conversations not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
- Confirm the API key has customer, conversation, and note permissions.
**Customer lookup issues**
- Karla matches customers by the order email. If the email in Kustomer differs
from the order (aliases, typos), Karla creates a new customer record instead
of linking to an existing one.
**Wrong Kustomer workspace**
- Double-check the **Organization** field is just the label (`yourbrand`) — no
`https://`, no `.kustomerapp.com`, no trailing path.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Zendesk](./zendesk) — native Zendesk integration setup.
- [Gorgias](./gorgias) — native Gorgias integration setup.
- [Dixa](./dixa) — native Dixa integration setup.
- [Intercom](./intercom) — native Intercom integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integration and automation](../integration-and-automation) — auto-refunds,
routing rules, and custom transformations.
---
## Intercom
Source: https://gokarla.io/docs/guides/resolve/integrations/intercom
# Intercom
:::info
The Intercom integration creates a structured ticket in your Intercom workspace
whenever a customer submits a Resolve claim. Photos, affected items, order
context, and the customer's resolution preference are attached automatically.
:::
## What you need
Before you start, gather:
- **Intercom admin access** — to create a private app and access token in the
Developer Hub.
- **An Intercom access token** — created under **Settings → Integrations →
Developer Hub** inside a private app's **Authentication** section. Intercom
uses **bearer-token authentication**, so unlike Zendesk or Gorgias there is
no account email or subdomain to provide.
- **Your Intercom data region** — US (`api.intercom.io`), EU
(`api.eu.intercom.io`), or AU (`api.au.intercom.io`). Karla routes API calls
to the host that matches your workspace.
- **A ticket type ID** — the Intercom ticket type new claim tickets are created
with. This is required before you can enable the integration.
Karla authenticates with your access token only — not your Intercom account
password.
## Connect Intercom for ticket creation
### 1. Create an access token in Intercom
In Intercom, open **Settings → Integrations → Developer Hub** and create (or
open) a **private app**.
Under the app's **Authentication** section, copy the **Access token**.
Name the app something recognizable — e.g. `Karla Resolve Integration`.
:::warning
Treat the access token like a password. Do not share it in email or chat —
enter it only in the Karla portal.
:::
The token needs permission to create tickets and attach tags in your Intercom
workspace.
### 2. Note your data region
Intercom workspaces are hosted in one of three regions. Pick the one that matches
your workspace:
| Region | API host |
| ------ | -------------------- |
| US | `api.intercom.io` |
| EU | `api.eu.intercom.io` |
| AU | `api.au.intercom.io` |
If you are unsure, check your Intercom workspace settings or ask your Intercom
admin which region your account uses.
### 3. Find your ticket type ID
Intercom creates tickets against a **ticket type**. Karla needs the ID of the
type new claim tickets should use.
Find it in Intercom under your ticket type settings, or list ticket types via
the Intercom API. The value looks like:
```text title="Ticket type ID"
1234567
```
Enter the ID exactly as Intercom shows it — not the display name.
### 4. Connect Intercom in the Karla portal
In the [Karla portal](https://portal.gokarla.io/), navigate to
**Settings → Integrations** and select **Intercom**.
Under **API Configuration**, paste your **Access Token** and save it. Karla
stores it in a secret manager and shows only a masked preview afterward.
### 5. Configure integration settings
Once the token is saved, the **Integration Settings** unlock:
| Field | Value |
| ------------------------------- | ----------------------------------------------------------- |
| **Data Region** | US, EU, or AU — matches your Intercom workspace |
| **Ticket Type ID** | The ticket type new claim tickets are created with |
| **Admin Assignee ID** | Optional admin to assign new tickets to |
| **Team Assignee ID** | Optional team to assign new tickets to |
| **Tag Admin ID** | Optional admin used when attaching template tags to tickets |
| **Skip Customer Notifications** | When on, Intercom does not notify the customer on creation |
Save the ticket type ID, then toggle the integration on. New Resolve claims
will create tickets in Intercom automatically.
:::note
The integration cannot be enabled until a ticket type ID is saved — Intercom
creates tickets against a type, so the ID is required.
:::
:::note
If you do not see Intercom under **Settings → Integrations**, contact your
account manager — the integration may need to be enabled for your shop first.
:::
### 6. Optional settings
One optional setting lives alongside the connection:
- **Ticket templates** — customize the subject, body, tags, and attachments
per claim reason. See
[Helpdesk integrations → Ticket templates](./overview#ticket-templates).
## What Karla creates in Intercom
When a customer submits a Resolve claim, Karla opens an Intercom ticket with:
- **Subject and message** mapped from the claim reason and customer notes.
- **Customer** matched or created from the order email.
- **Tags** reflecting the Resolve flow type, resolution preference, and
shipment phase (configured per shop).
- **Attachments** — claim photos and signatures uploaded to the ticket.
- **Order and shipment context** in the ticket — order number, carrier,
tracking number, affected line items.
Your agents see a complete ticket without looking up the order elsewhere.
## Troubleshooting
**Cannot enable the integration**
- Save a **Ticket Type ID** first — the toggle stays disabled until one is
stored.
**Tickets not appearing**
- Confirm the integration toggle is enabled in the Karla portal.
- Confirm the ticket type ID matches a real Intercom ticket type.
- Confirm the **Data Region** matches your Intercom workspace.
- Confirm Resolve is enabled and customers are submitting claims through an
active Resolve flow.
**Authentication failed after saving**
- Confirm the access token was copied in full — no leading or trailing spaces.
- Confirm the token was created in the Developer Hub and is not expired or
revoked.
**Wrong Intercom workspace or region**
- Double-check the **Data Region** — EU and US workspaces use different API
hosts. A mismatched region returns authentication or not-found errors.
**Tags not applied**
- If you use template tags, confirm a **Tag Admin ID** is saved. Without it,
Karla skips tagging.
## Where to next
- [Helpdesk integrations overview](./overview) — other connection options.
- [Zendesk](./zendesk) — native Zendesk integration setup.
- [Gorgias](./gorgias) — native Gorgias integration setup.
- [Dixa](./dixa) — native Dixa integration setup.
- [Kustomer](./kustomer) — native Kustomer integration setup.
- [Webhooks](./webhooks) — push claim events to a custom endpoint instead.
- [Data processing](../data-processing) — the full claim payload shape.
- [Integration and automation](../integration-and-automation) — auto-refunds,
routing rules, and custom transformations.
- [Integrate in your shop](../integrate-in-your-shop) — embed Resolve on your
storefront via the Browser SDK.
---
## Email
Source: https://gokarla.io/docs/guides/resolve/integrations/email
# Email Helpdesk
:::info
The Email Helpdesk is a fallback for shops without a Gorgias, Zendesk, Dixa,
Front, Kustomer, or Intercom integration. Every Resolve claim is emailed to a
support inbox you choose, as a ticket-style email — no API keys, no subdomain.
:::
## What you need
Just one thing:
- **A recipient inbox** — the support email address that should receive the
claim emails, e.g. `support@example.com`.
There are no credentials to create. If you already run a native helpdesk
(Gorgias, Zendesk, Dixa, Front, Kustomer, or Intercom), use that instead — the
email fallback is for shops that don't.
## Steps
Claim email settings live in the [Karla portal](https://portal.gokarla.io/)
under **Resolve → Claim Emails** — the recipient inbox, the fallback toggle, the
carrier affidavit, and the per-reason subject and body are all on that one page.
:::note
**Settings → Integrations → Email Helpdesk** still exists, but it only links
across to **Resolve → Claim Emails**; nothing is configured there anymore.
:::
### 1. Set the recipient inbox
Open **Resolve → Claim Emails**. In the **Recipient Inbox** card, enter the
support email address under **Recipient Email** and save it. Saving an address
is required before you can enable the fallback.
### 2. Enable the fallback
Toggle **Email Helpdesk Fallback** on. New Resolve claims are now emailed to your
inbox as ticket emails, with order context, affected items, and the customer's
resolution preference.
:::note
If you do not see **Claim Emails** under Resolve, contact your account manager —
it may need to be enabled for your shop first.
:::
## Carrier affidavit (optional)
You can attach a carrier affidavit PDF to investigation (not-received) claim
emails, useful for carrier disputes. Turn on **Carrier Affidavit** on the same
page and provide:
- **Sender Address** — your postal sender line, printed on the PDF.
- **Type of Goods** — what your parcels contain (the "Inhalt" line on the PDF).
- **Main Carrier** — which carrier's form to use, or **Automatic** to route by
the shipment's carrier.
## Customizing the email content
Under **Claim Email Content** on the same page, you can override the **subject**
and **body** per claim reason. Leave a reason untouched to keep Karla's shipped
wording.
## Where to next
- [Helpdesk integrations overview](./overview) — native connection options.
- [Zendesk](./zendesk) · [Gorgias](./gorgias) · [Dixa](./dixa) · [Front](./front) · [Kustomer](./kustomer) · [Intercom](./intercom) — native
integrations with structured ticket creation.
- [Webhooks](./webhooks) — push claim events to any custom endpoint.
- [Data processing](../data-processing) — the full claim payload shape.
---
## Webhooks
Source: https://gokarla.io/docs/guides/resolve/integrations/webhooks
# Webhooks
:::info
Webhooks let you connect Resolve to **any** helpdesk or internal tool. Karla
POSTs a structured claim event to your endpoint the moment a customer submits
— you (or a middleware layer) translate that payload into a ticket.
:::
This is the most flexible integration path. Use it when your helpdesk is not
yet supported as a native integration, when you need a custom ticket format,
or when you want to fan out the same claim to multiple systems.
## Claim events
Resolve emits two claim events:
| Event | Ref | When |
| ------------- | ---------------- | ------------------------------------ |
| Claim created | `claims/created` | Customer submits a new Resolve claim |
| Claim updated | `claims/updated` | Claim status or details change |
For the full payload shape — including `event_data`, order context, shipment
data, and photo URLs — see [Claim events](/docs/platform/events/claims) and
[Data processing](../data-processing).
## Set up a webhook in the portal
The fastest way to start receiving claim events:
1. Open the [Karla portal](https://portal.gokarla.io/).
2. Go to **Settings → Webhooks**.
3. Add your destination URL.
4. Select claim events — at minimum `claims/created`.
5. Save.
Karla starts delivering events immediately. Your endpoint must accept HTTPS
POST requests with a valid TLS certificate.
For programmatic setup, signature verification, retries, and receiver
implementation details, see the general
[Webhooks guide](/docs/guides/notify/webhooks).
## Map the payload to your helpdesk
Karla sends the raw structured claim — it does not shape the payload for your
specific helpdesk. That is by design: you control how the ticket looks.
A typical receiver flow:
1. **Receive** the `claims/created` webhook from Karla.
2. **Extract** customer email, reason, affected items, and photo URLs from
`event_data` and `context`.
3. **Create a ticket** in your helpdesk via its API — Zendesk, Freshdesk,
Intercom, a custom internal tool, or anything with an HTTP API.
4. **Attach evidence** — download photo URLs from the payload and attach them
to the ticket.
:::tip Middleware connectors
If you do not want to build a receiver yourself, tools like Zapier, Make, or
n8n can accept Karla webhooks and call your helpdesk API. Point the webhook
at the connector and map fields visually.
:::
## Example: minimal claim payload
The webhook body follows the standard Karla event envelope. The claim-specific
fields live in `event_data`:
```jsx title="claims/created event_data (abbreviated)"
{
"ref": "claims/created",
"event_group": "claim_created",
"event_data": {
"claim_id": "38fdc365-7de9-4313-afbd-0ed23717c5e0",
"reason": "damage",
"resolution_preference": "refund",
"description": "Package was damaged on the right side",
"selected_items": [
{
"sku": "ABCD3",
"title": "Product Title",
"quantity": 1
}
],
"image_urls": [
"https://cdn.gokarla.io/.../claim"
]
},
"context": {
"order": { "order_number": "0000001", "..." : "..." },
"customer": { "email": "customer@example.com", "..." : "..." },
"shipments": [ "..." ]
}
}
```
See [Claim events](/docs/platform/events/claims) for the complete payload with
full order and shipment context.
## Security
- All webhook traffic uses **HTTPS** with TLS 1.2 or higher.
- Verify webhook signatures using the secret configured in the portal. Karla
signs every delivery with a `Karla-Signature` header:
```text title="Karla-Signature header"
Karla-Signature: t=1735689600,v1=5f2b...c9
```
`t` is the Unix timestamp of the delivery and `v1` is the hex-encoded
HMAC-SHA256 of `{t}.{raw request body}`, keyed with your webhook secret.
Recompute it over the **raw** body — not a re-serialized copy — and compare
with a constant-time check. See
[Webhooks → Verifying signatures](/docs/guides/notify/webhooks) for a worked
example.
- **Static IP egress** is available as a premium add-on if your receiver sits
behind a firewall and you need to allow-list a fixed source. Talk to your
account manager if you need this.
## Native integrations vs webhooks
| | Native integration | Webhooks |
| ----------------- | -------------------------------------------------------- | ------------------------------------------ |
| Setup | Portal — credentials only | Portal or API — endpoint + event selection |
| Ticket formatting | Handled by Karla | You (or your middleware) |
| Helpdesk support | Zendesk, Gorgias, Dixa, Front, Kustomer, Intercom, Email | Any tool with an HTTP API |
| Claim automation | Self-serve rule sets in portal | Custom middleware logic |
| Best for | Standard ticket creation | Custom shapes, multi-destination fan-out |
If Zendesk, Gorgias, Dixa, Front, Kustomer, or Intercom is your helpdesk, the
native [Zendesk](./zendesk), [Gorgias](./gorgias), [Dixa](./dixa),
[Front](./front), [Kustomer](./kustomer), or [Intercom](./intercom) integration
is simpler — Karla handles authentication and ticket formatting for you.
## Where to next
- [Zendesk](./zendesk) — native Zendesk integration with self-service portal
setup.
- [Gorgias](./gorgias) — native Gorgias integration with Help Center embed.
- [Kustomer](./kustomer) — native Kustomer integration with conversation and
note creation.
- [Intercom](./intercom) — native Intercom integration with ticket type
configuration.
- [Claim automation](../claim-automation) — automate refunds and replacements
with portal rule sets.
- [Helpdesk integrations overview](./overview) — compare connection options.
- [Webhooks guide](/docs/guides/notify/webhooks) — receiver implementation,
retries, and signature verification.
- [Claim events](/docs/platform/events/claims) — full event catalog and
payload reference.
---
## Integrate in your shop
Source: https://gokarla.io/docs/guides/resolve/integrate-in-your-shop
# Integrate in your shop
Resolve pages embed into your shop website through the Karla
[Browser SDK](/docs/platform/browser-sdk) — a single script tag plus a
container div.
## Embed the resolve widget
Add a container div and the bundle script to the page where you want the
resolve flow to render, and set `data-starter-page="resolve"` so the SDK
loads the resolve entry point:
```html
```
Replace `my-shop-slug` with your own shop slug (find it in the
[portal](https://portal.gokarla.io/) under your shop profile).
For all supported script attributes, order lookup methods, debug options, and
advanced configuration, see the [Browser SDK](/docs/platform/browser-sdk)
reference.
## Test your embed
Once the page is published (e.g. `https://your-shop-domain/resolve`), add
order identifiers as URL parameters to preview a real resolution flow:
- ZIP code lookup: `https://your-shop-domain/resolve?orderNumber=00001&zipCode=10119`
- Token-based lookup: `https://your-shop-domain/resolve?orderNumber=00001&token=abc123`
:::tip Tokens unlock extra actions on the order
When you link to the resolve page with a **token** instead of a ZIP code,
Karla treats the visitor as authenticated for that specific order. We
reserve advanced, order-scoped operations (things like cancellation flows
and similar sensitive actions) for token-authenticated sessions, and the
set of capabilities behind the token keeps growing over time.
Token lookup is **enabled by default** on every shop (Shopify and others),
and every notification Karla sends — including the resolve page URL in
shipping emails — already carries the token for that order. You can also
retrieve a token-protected URL for any order through our public
[API](/docs/api-reference), so you can embed secure deep links in your own
emails, flows, or support tools.
:::
## Skip issue selection
If you want to route customers directly into a specific resolution flow
(e.g. a "Report damaged item" link that goes straight to the defective
flow), add the `flowType` URL parameter:
- `?flowType=defective`
- `?flowType=notReceived`
- `?flowType=missingProduct`
- `?flowType=wrongProduct`
- `?flowType=return`
- `?flowType=dissatisfiedWithProduct`
- `?flowType=support`
## Using the API directly
If you'd rather build your own resolve UI from scratch, see the
[Claims API](/docs/api-reference).
---
# Shops
> Connect your shop — Shopify, Shopware, WooCommerce, or headless
## Overview
Source: https://gokarla.io/docs/guides/shops/overview
# Shops
Karla meets your shop wherever it lives. Native integrations for Shopify,
Shopware, and WooCommerce cover 95% of merchants in a few clicks — and a clean
public API lets the other 5% build whatever they want.
## How the integration works
Karla is the post-purchase layer on top of your storefront. Your shop is the
source of truth for orders; Karla is the source of truth for the journey after
the order is placed — shipments, carrier events, tracking pages, notifications,
resolution flows.
The integration is deliberately boring:
1. Your shop sends us **orders** as they're created, updated, or cancelled.
2. Your shop (or your WMS) sends us **shipments** with a tracking number and
carrier.
3. Karla takes over from there — polling the carrier, normalizing statuses,
powering the tracking page, triggering notifications, surfacing anomalies
for resolution.
That's it. No heavy middleware, no data lake, no re-architecting your stack.
## What we pull from your shop
Order number, totals, line items, fulfillment status, currency, and
customer-facing metadata.
Name, email, phone (if available), locale preference, and shipping address —
only what we need to personalize tracking pages and messages.
Tracking number(s), carrier identifier, fulfillment line-items. Karla
handles the rest — carrier polling, status normalization, ETA.
Webhooks for creation, update, and cancellation. We only ingest what changes
— no bulk syncing, no nightly jobs.
## Pick your path
Most merchants plug Karla in via one of our native integrations — pick the one
that matches your storefront and follow the step-by-step setup.
For teams who want to ship something custom — a proprietary tracking
experience, a mobile app, an agent that surfaces shipment state in Slack —
Karla is also a pure API. Skip the plugins, call the endpoints directly, and
build on top.
## Build your own: Karla as a platform
If you can write code, you can build on Karla. Every integration in this
section is a thin layer over the same public API — there's nothing
Shopify-specific or Shopware-specific under the hood.
That means you can:
- Power a **custom tracking page** on your own domain, styled exactly the way
you want.
- Embed shipment state into your **mobile app**, an internal dashboard, or a
Slack channel.
- Orchestrate **automations** off of Karla events — send an email when a
shipment stalls, trigger a refund flow on a failed delivery.
- Wire Karla into an **AI agent** that handles "where is my order?" without a
human ever touching it.
We built Karla to be headless-first — every UI we ship (tracking page, portal,
resolve) is just a reference implementation on top of the same API you have
access to. If you'd rather design your own experience, the
[Headless guide](/docs/guides/shops/headless) walks through the full data
model and the endpoints you'll need.
## Where to next
- Got a Shopify store? Start with [Shopify](/docs/guides/shops/shopify).
- Enable Shopify post-purchase money-makers:
[one-click upsell](/docs/guides/shops/post-purchase-upsell) and
[Thank you survey](/docs/guides/shops/thank-you-survey).
- On Shopware? Follow the [Shopware](/docs/guides/shops/shopware) setup.
- Running WooCommerce? Set up webhooks in
[WooCommerce](/docs/guides/shops/woocommerce) — no plugin required.
- Building your own storefront or going fully headless?
[Headless](/docs/guides/shops/headless) is where you want to be.
---
## Shopify
Source: https://gokarla.io/docs/guides/shops/shopify
# Shopify
:::info
The Shopify integration allows Karla to retrieve order updates from your shop and display them on your customers' tracking pages (e.g., purchased products, shipping address, etc.) as well as retrieve all tracking numbers to provide corresponding tracking updates.
:::
## Install the Shopify App
Install our [Shopify App](https://apps.shopify.com/karla-1) and follow the onboarding steps.
## Post-purchase upsell and survey
After the app is installed, you can enable two checkout surfaces merchants
configure themselves — no custom implementation required:
| Feature | Where buyers see it | Setup guide |
| -------------------- | ------------------------------------------------------------ | --------------------------------------------------------------- |
| **One-click upsell** | Shopify post-purchase page (after payment, before Thank you) | [Post-purchase upsell](/docs/guides/shops/post-purchase-upsell) |
| **Thank you survey** | Shopify Thank you page | [Thank you survey](/docs/guides/shops/thank-you-survey) |
Both are configured in the Karla app and activated once in Shopify checkout
settings / the checkout editor.
### Tracking page links
By default, the Karla app provisions a tracking page on your Shopify domain (including all market domains), that you can use right away:
:::info Shopify Markets
If your markets use subfolder paths (e.g., `/de`, `/de-at`), include the market prefix: `https://[yourdomain]/de-at/apps/karla/track`. For subdomain or separate domain markets, simply use that domain as `[yourdomain]`.
:::
#### Order Tracking
- Logged-in customers see their recent orders. Guests see the order finder.
- `https://[yourdomain]/apps/karla/track`
- Direct link for logged-in customers:
- `https://[yourdomain]/apps/karla/track?orderNumber=00001`
- Direct link for guests (zip code required):
- `https://[yourdomain]/apps/karla/track?orderNumber=00001&zipCode=10119`
#### Issue Resolution
- Logged-in customers see their recent orders. Guests see the order finder.
- `https://[yourdomain]/apps/karla/resolve`
- Direct link for logged-in customers:
- `https://[yourdomain]/apps/karla/resolve?orderNumber=00001`
- Direct link for guests (zip code required):
- `https://[yourdomain]/apps/karla/resolve?orderNumber=00001&zipCode=10119`
:::info Deeplinks
`00001` (order number) and `10119` (zip code) are example
values. Replace them with your customer's actual order number and zip
code to create a deep link to any specific order. Zip code is only required if the customer is not logged in.
:::
## Advanced: Setting up your own Tracking Page template
You can add the Karla tracking widget to any Shopify template of your choice.
:::danger Do NOT add the tracking widget to your default page template
Adding the widget to your default page template will override **all** pages that use that template (info pages, help center, guides, etc.). Always use a dedicated template.
:::
### Step 1: Add the tracking widget to a theme (pick one method)
Our app includes a ready-made **Tracking Page** block that you can add via the theme editor:
1. Go to **Online Store → Themes → Customize**
2. In the top navigation, select **Pages** → choose your tracking page
3. Click **Add section** and look for the **Tracking Page** block (under "Apps")
4. Configure language and starting view in the block settings
5. Remove the default content section if you want the tracking widget to be the only content
6. Click **Save**

This approach automatically inherits your theme's fonts and colors, supports logged-in customers (they will see a very simple list of their latest orders to pick if they are logged in and no orderNumber query parameter was given), and requires no code.
### Step 2: Create a page based on the template
1. In your Shopify admin, go to **Online Store → Pages**
2. Click **Add page**
3. Set the title (e.g., "Track your order")
4. Select the template
5. Publish the page

## Advanced: Campaign attribution
Our Shopify app also allows you to track which orders come from your Karla campaigns. For a complete overview of attribution methods across all platforms, see the [Campaign Attribution Overview](/docs/guides/tracking-page/attribution).
### Method 1: Shopify app
All call-to-action links in portal campaigns automatically carry Karla's attribution parameters — `ref=karla`, `karla_source`, `karla_medium`, and `karla_campaign` (plus originating-order identifiers on product promotions). No link configuration is needed.
The Karla app's attribution pixel — enabled under **Settings → Campaign Attribution** in the app — captures these parameters when the customer lands in your store and sends them to Karla when the checkout completes.
For the full parameter reference, consent options, and how to verify the chain end-to-end, see [Campaign attribution](/docs/guides/tracking-page/attribution).
### Method 2: Discount codes
Simply add a discount code to your campaign in the [Karla portal](https://portal.gokarla.io). Orders using this discount will be automatically attributed to the campaign.
**Verifying orders in Shopify:**
Navigate to **Orders** → Filter by **Discount code** to see all orders that used your campaign discount.
For complete details on discount code attribution, best practices, and limitations, see [Discount code attribution](/docs/guides/tracking-page/attribution#discount-code-attribution).
## Customer Segments via Order Tags
Karla automatically reads tags from your Shopify orders and customers and turns each one into a segment you can target in [campaigns](/docs/guides/portal/campaigns), triggers, and A/B tests. No setup required on the Karla side — just tag your orders (or customers) in Shopify and Karla picks them up.
### How it works
- Each tag on the Shopify order — and each tag on its customer — becomes a segment in Karla with the prefix `Shopify.tag.` followed by the exact tag name.
- Karla re-reads tags **every time an order is created or updated** in Shopify, so tags added later are picked up automatically.
- Multiple tags on one order produce multiple segments.
**Examples:**
| Order tag | Karla segment |
| ---------------- | ---------------------------- |
| `vip` | `Shopify.tag.vip` |
| `bought-starter` | `Shopify.tag.bought-starter` |
| `market-de` | `Shopify.tag.market-de` |
### Driving segments with Shopify Flow
Order tags become powerful when combined with [Shopify Flow](https://help.shopify.com/en/manual/shopify-flow). Flow can stamp an order with a tag based on anything Shopify knows — customer attributes, line items, totals, location, Shopify Customer Segments, even data from third-party apps. Karla then turns those tags into segments.
**Example — VIP customers see a VIP banner:**
In Shopify Admin → **Apps → Shopify Flow → Create workflow**:
1. **Trigger:** `Order created`
2. **Condition:** customer has tag `vip`
3. **Action:** `Add order tags` → `vip`
When a VIP customer places an order, Shopify stamps it with `vip`, Karla receives the webhook, and a campaign targeting segment `Shopify.tag.vip` runs on that customer's tracking page.
**Example — cross-sell on a specific product:**
1. **Trigger:** `Order created`
2. **Condition:** any line item matches the "Starter Kit" product (or SKU)
3. **Action:** `Add order tags` → `bought-starter`
Karla emits segment `Shopify.tag.bought-starter`; a product campaign recommending related items targets that segment.
### Common Flow patterns
| Goal | Flow condition | Order tag | Karla segment |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------- | ---------------------------- |
| VIP banner | customer has tag `vip` | `vip` | `Shopify.tag.vip` |
| First-time buyer welcome | customer's number of orders equals 1 | `first-time` | `Shopify.tag.first-time` |
| Loyalty offer | customer's number of orders is 3 or more | `loyal` | `Shopify.tag.loyal` |
| Free-shipping VIP | order total ≥ 100 | `high-value` | `Shopify.tag.high-value` |
| German-market campaign | shipping country is DE | `market-de` | `Shopify.tag.market-de` |
| Cross-sell on specific product | any line item matches a target product or SKU | `bought-starter` | `Shopify.tag.bought-starter` |
| Shopify Customer Segment membership | trigger _Customer joined segment_ → tag the customer → on order, mirror the customer tag into an order tag | `seg-vip` | `Shopify.tag.seg-vip` |
### Things to know
- **Tags are case-sensitive** — `VIP` and `vip` produce different segments. Pick one convention and stick to it.
- **Tags cannot contain commas** — Shopify uses commas as the separator. Use hyphens or underscores instead (e.g., `wholesale-b2b`).
- **Spaces inside a tag are preserved** — `"first time buyer"` becomes `Shopify.tag.first time buyer`. Hyphens read more cleanly in segment lists.
- **Empty tags are ignored**, and surrounding whitespace is trimmed.
- **Once an order is fulfilled, changing its tags won't switch the campaign that shipment shows.** Campaign assignment is locked at fulfillment. See [How segmentation works](/docs/guides/portal/campaigns#how-segmentation-works).
:::tip
Karla reads customer tags and order tags identically — both become `Shopify.tag.*` segments. For order-specific targeting, prefer order tags: Shopify Flow can read any customer attribute and write it as an order tag, so each order carries exactly the segments you want.
:::
📚 **Shopify docs:**
- [Tag customers and orders](https://help.shopify.com/en/manual/customers/manage-customers/tag-customers)
- [Shopify Flow overview](https://help.shopify.com/en/manual/shopify-flow)
- [Add order tags action](https://help.shopify.com/en/manual/shopify-flow/reference/actions/add-order-tags)
## Advanced: Custom Properties
Add custom properties to your Shopify orders to enhance your customers' delivery experience with Karla.
### Understanding Scopes
Karla reads custom data from Shopify **order attributes** (also called note
attributes), always prefixed with `_karla_`:
- Set them with Shopify `attributes` — cart attributes become order
attributes at checkout
- They apply to the entire order; per-product data (like estimated ship
dates) is keyed by variant ID inside the attribute value
### Order Attributes
These `attributes` will appear in the `Additional details` section of your order admin panel.
#### Estimated ship dates
Specify when each product is expected to ship using the
`_karla_estimated_ship_dates` order attribute. Its value is a JSON object
keyed by the **numeric variant ID** of the line item:
```json
{ "44123456789": { "start": "2025-10-23", "end": "2025-10-30" } }
```
Providing both `start` and `end` creates a shipping window (e.g., "Ships between Oct 23 and Oct 30"). Providing only `start` displays a single estimated date. An `end` earlier than `start` is discarded.
- **Date formats accepted:** any [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date string (preferred), or common date strings like `23.10.2025` or `10/23/2025`
- **Scope**: Per product variant, set once on the order
#### Order attribution variables
The Karla Shopify app reads these cart attributes when an order is placed and
forwards them to the order's `order_analytics` payload. You can set them
yourself (via cart AJAX or theme liquid) to own the full attribution logic.
See [Campaign attribution](/docs/guides/tracking-page/attribution) for the
complete flow.
These variables are:
- `_karla_campaign`: Campaign identifier
- `_karla_captured_at`: Timestamp when the attribution was first captured
- `_karla_landing_path`: Path on your shop where the customer landed
- `_karla_landing_url`: Full URL where the customer landed
- `_karla_medium`: Marketing medium (e.g., email, banner, push notification)
- `_karla_referrer`: HTTP referrer URL
- `_karla_source`: Traffic source identifier (e.g., trackpages, karla-lounge)
### Complete Implementation Examples
#### Example 1: Setting Estimated Ship Dates (AJAX)
Set the estimated ship dates as a cart attribute — Shopify turns cart
attributes into order attributes at checkout:
```liquid
```
Use the numeric variant ID of each line item as the key, and include one
entry per product that needs a ship date.
#### Example 2: Adding Order Attribute (Cart Page)
There are two methods depending on your theme type:
##### Method A: Traditional Form (Older Themes)
If your theme uses traditional cart forms (typically older themes or custom implementations):
```liquid
```
##### Method B: AJAX Cart (Modern Themes)
Most modern Shopify themes (Dawn, Refresh, etc.) use AJAX for cart operations. For these themes, add this JavaScript to your theme file (e.g., `theme.liquid`), before the closing `