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

# Embed SDK

> Modal checkout on external merchant sites via embed.iife.js.

## Overview

The Join Markt Embed SDK drops modal checkout onto an external merchant site. Buyers stay on the merchant page; payment and delivery still run on Join Markt hosted checkout inside an iframe.

```html theme={null}
<script src="https://YOUR_APP_ORIGIN/embed/embed.iife.js" defer></script>
```

Globals: `window.Markt` and alias `window.MarktEmbed`.

Local demo:

```text theme={null}
http://localhost:3000/embed/demo.html?productId=YOUR_PRODUCT_ID&variantId=OPTIONAL_VARIANT_ID
```

Dashboard: product page → **Embed Checkout**.

## Quick start

```html theme={null}
<script src="https://YOUR_APP_ORIGIN/embed/embed.iife.js" defer></script>
<script>
  document.addEventListener('DOMContentLoaded', () => {
    Markt.init()
  })
</script>

<button
  data-markt-product-id="PRODUCT_CUID"
  data-markt-variant-id="VARIANT_UUID"
  data-markt-quantity="1"
  data-markt-theme="auto"
>
  Buy Now
</button>
```

Save the product once so variant UUIDs stay stable before shipping snippets.

## Data attributes

| Attribute                | Required          | Notes                                 |
| ------------------------ | ----------------- | ------------------------------------- |
| `data-markt-product-id`  | Yes               | Product CUID                          |
| `data-markt-variant-id`  | If variants exist | Stable UUID                           |
| `data-markt-quantity`    | No                | Default 1, clamped 1-99               |
| `data-markt-theme`       | No                | auto, light, or dark                  |
| `data-markt-return-url`  | No                | Parent navigates after close when set |
| `data-markt-email`       | No                | Prefill                               |
| `data-markt-coupon-code` | No                | Prefill coupon                        |
| `data-markt-metadata`    | No                | JSON object of string values          |

## JavaScript API

### Markt.init

```js theme={null}
Markt.init({ nonce: 'optional-csp-nonce' })
```

Binds `[data-markt-product-id]`, observes late nodes, listens for close messages.

### Markt.open

```js theme={null}
Markt.open({
  items: [{ productId: '...', variantId: '...', quantity: 1 }],
  theme: 'auto',
  affiliateCode: 'partner_1',
  returnUrl: 'https://merchant.example/thanks',
  email: 'buyer@example.com',
  couponCode: 'SAVE10',
  metadata: { campaign: 'launch' },
})
```

Only `items[0]` is sent. Multi-item carts are not supported in embed — use storefront checkout start instead.

### Markt.close

Hides the overlay and blanks the iframe.

## Server round-trip

`open` POSTs to [Create Embed Checkout](/api/embed-checkout) and loads the returned URL (`?embed=1&theme=...`) in the iframe.

Rate limit: **30 requests / 60 seconds** per client.

## Close protocol

Checkout posts to the parent:

```json theme={null}
{ "type": "markt-embed-close", "returnUrl": "https://...", "paid": true }
```

SDK closes the modal. If `returnUrl` is present, parent navigates there.

## Affiliates

1. Explicit `affiliateCode`
2. `?ref=` on the merchant page
3. `markt_affiliate` cookie

Stored on the order as `referralCode`.

## CSP

```http theme={null}
Content-Security-Policy:
  frame-src https://YOUR_APP_ORIGIN;
  script-src 'self' 'nonce-YOUR_NONCE' https://YOUR_APP_ORIGIN;
```

Join Markt allows `frame-ancestors *` on `/embed/*` and `/checkout/*`.

## Constraints

* Private / on-hold products rejected
* Variants required when the product defines them
* Quantity clamped 1-99
* Debounce clicks to stay under the rate limit

## Troubleshooting

| Symptom            | Check                                                 |
| ------------------ | ----------------------------------------------------- |
| Click does nothing | Script loaded? `Markt.init()` called? Console errors? |
| API 404            | Product id, banned store, wrong origin                |
| API 400 variant    | Save product, pass stable variant UUID                |
| 429                | Debounce; 30/min budget                               |
| Modal behind UI    | Competing z-index                                     |
