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

# Embedded flow

> Embed Kombo Connect into your app for the most seamless experience.

If you've gone through the general [Kombo Connect](./introduction) documentation,
you'll know there are
[different ways of using the flow](./introduction#getting-started). Our embedded flow
provides the most seamless experience to your customers but also involves some
engineering on your side. In this guide, we'll go over what that means exactly.

## Implementing the flow

The embedded flow requires you to:

* Add an **endpoint** to your back-end for initiating the flow
* Add a **button** to your frontend to show the flow to your user using the SDK
* React to a flow being completed through the "activation token" returned by the SDK or by listening to a webhook

Let's go over each of these steps in detail.

### Adding the endpoints

Both endpoints are mostly just wrappers around endpoints of the Kombo API and
mainly exist for security reasons (so that malicious actors can't set up
arbitrary integrations in your Kombo environment).

#### Initiating the flow

The first one initializes the flow by calling the Kombo API and returns a link
that we then use in the frontend:

```js Node.js (Express + Axios) theme={null}
app.post('/integrations/kombo/init', async (req, res) => {
  // TODO: Get user details from your database
  const user = await getUser()

  const response = await axios.post(
    'https://api.kombo.dev/v1/connect/create-link',
    {
      end_user_email: user.email,
      end_user_organization_name: user.company.name,
      end_user_origin_id: user.company.id,

      integration_category: 'HRIS',
    },
    {
      headers: {
        authorization: `Bearer ${KOMBO_API_KEY}`,
      },
    },
  )

  res.send({ link: response.data.data.link })
})
```

The `end_user_*` fields identify which of your customers an integration belongs to:

* **`end_user_email`** (required): Contact email for this end user. Used as a label in the dashboard and included in webhooks.
* **`end_user_organization_name`** (required): Company name. Used as a label in the dashboard and included in webhooks.
* **`end_user_origin_id`** (optional): Your internal ID for this customer. Echoed back in webhooks and API responses so you can map integrations to your own records.

These fields are metadata — they do not affect integration identity. Changing the email or organization name in a subsequent `create-link` call with the same `end_user_origin_id` does **not** update an existing integration; it creates a new flow link.

<Warning>
  Kombo does **not** deduplicate integrations based on these fields. Each
  completed flow creates a new integration. You are responsible for preventing
  customers from connecting the same tool twice. Use the [reconnection
  link](../../v1/post-integrations-integration-id-relink) if a customer needs to
  update their credentials for an existing integration.
</Warning>

#### Reacting to the flow being completed

After your user completes the flow, you can retrieve the integration details and store them in your database for future use. There are two ways to achieve this:

1. By using the ["Get integration by token" endpoint](../../v1/get-connect-integration-by-token-token)
2. By listening to the `integration-created` webhook

**Option 1: Using the endpoint**

The activation token is returned from the frontend after the user completes the integration flow. You can use this token to retrieve the integration details via the ["Get integration by token" endpoint](../../v1/get-connect-integration-by-token-token) and store them in your database.

Here's how you might implement the activation endpoint:

```js Node.js (Express + Axios) theme={null}
app.post('/integrations/kombo/activate', async (req, res) => {
  const response = await axios.get(
    `https://api.kombo.dev/v1/connect/integration-by-token/${req.body.token}`,
    {
      headers: {
        authorization: `Bearer ${KOMBO_API_KEY}`,
      },
    },
  )

  const integrationId = response.data.data.id

  // TODO: Store the integration ID in your database

  res.sendStatus(200)
})
```

**Option 2: Listening to the `integration-created` Webhook**

Alternatively, you can set up a webhook endpoint on your backend to listen for the `integration-created` event that Kombo sends when a new integration is created. This webhook contains the integration ID and other relevant details, allowing you to associate the integration with your user in your database.

Here's how you might set up the webhook endpoint:

```js Node.js (Express) theme={null}
app.post('/webhooks/kombo/integration-created', async (req, res) => {
  const integration = req.body.data

  // TODO: Verify the webhook signature for security purposes

  // TODO: Store the integration ID in your database

  res.sendStatus(200)
})
```

* Make sure to [verify the webhook signature](../../guides/webhooks#validate-the-data) to ensure that the request comes from Kombo.
* Make sure to set up the webhook in the [dashboard](https://app.kombo.dev/configuration/webhooks).

### Adding the button

For now, we're all set on the back-end side, so let's switch to the front-end:

Here we'll have to add a button that lets your users start the flow. Most of our
customers already have an "Integrations" page within their product's settings.
If you do, too, then that's the perfect place to add the button.

How exactly you're going to do this will depend on your tech stack, but it's
probably going to look something like this:

<CodeGroup>
  ```jsx React theme={null}
  <button onClick={() => connectHris()}>Connect HRIS</button>
  ```

  ```jsx Vue.js theme={null}
  <button @click="connectHris()">
    Connect HRIS
  </button>
  ```

  ```html HTML theme={null}
  <button onclick="connectHris()">Connect HRIS</button>
  ```
</CodeGroup>

<br />

<Note>
  Right now, we require you to specify the integration category when
  initializing the flow, so you'll likely want to label your button accordingly
  (e.g., "Connect HRIS" or "Connect ATS").
</Note>

When a user clicks on the button, two things need to happen:

* An integration link has to be retrieved through your endpoint
* The embedded flow has to be started

#### Getting a link

Here's what the first part might look like:

```js JavaScript theme={null}
async function getKomboConnectLink() {
  // Note: The URL below points to *your* API and could be different
  const response = await fetch('/integrations/kombo/init')
  const data = await response.json()

  return data.link
}
```

#### Opening the flow

Now it's time to actually show the flow to the user. This can be through
[the @kombo-api/connect JavaScript library](https://www.npmjs.com/package/@kombo-api/connect).
It's tiny (about 50 lines of JavaScript as of now) and basically just
initializes an `<iframe>` to display the flow.

<Note>
  **Important:** Since the Kombo Connect flow is displayed in an iframe, you'll need to ensure your Content-Security-Policy allows it. Add `frame-src https://connect.kombo.dev` to your CSP header:

  ```
  Content-Security-Policy: frame-src https://connect.kombo.dev;
  ```
</Note>

Let's, first of all, add it as a dependency to our front-end:

<CodeGroup>
  ```bash npm theme={null}
  npm install @kombo-api/connect
  ```

  ```bash yarn theme={null}
  yarn add @kombo-api/connect
  ```

  ```bash pnpm theme={null}
  pnpm add @kombo-api/connect
  ```
</CodeGroup>

Then, import it like so:

```js JavaScript theme={null}
import { showKomboConnect } from '@kombo-api/connect'
```

##### Can't use npm packages or imports?

You can also load the library from the unpkg CDN:

```html HTML theme={null}
<script src="https://unpkg.com/@kombo-api/connect@1/dist/index.js"></script>
```

This makes the library available globally as `KomboConnect`.

#### Reacting to the flow being completed

After the user completes the flow, you'll receive an activation token. This token can be used to retrieve the integration details from Kombo. Depending on the method you choose (activation endpoint or webhook), you'll handle this token differently.

If you're using the activation endpoint, send the token to your backend:

```js JavaScript theme={null}
async function activateKomboIntegration(token) {
  // Note: The URL below points to *your* API and could be different
  const response = await fetch('/integrations/kombo/activate', {
    method: 'POST',
    body: JSON.stringify({ token }),
  })
}
```

If you're using the webhook method, you don't need to handle the activation token on the frontend. Instead, the webhook will notify your backend when a new integration is created.

### Putting all together

Now it's time to put it all together:

```js JavaScript theme={null}
// You can call this whatever you want (just attach this to your button)
async function connectHris() {
  // We wrote this function earlier (make sure to import/include it)
  const link = await getKomboConnectLink()

  const activationToken = await showKomboConnect(link)

  // Not necessary if you're reacting to the `integration-created` webhook
  await activateKomboIntegration(activationToken)
}
```

<Info>
  **What if the user doesn't finish?** No integration is created until the user
  completes the entire flow. Abandoned or closed flows leave no orphan records
  in Kombo. You can safely generate a new link via `POST /connect/create-link`
  for the user to retry. To avoid duplicate integrations for users who *do*
  complete the flow, track completed `integration_id`s on your side, ideally via
  webhook.
</Info>

And that's it! You've successfully embedded Kombo Connect!
