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

# Import Merchants

> Bulk-create and/or link up to 100 sub-merchants in a single request.

# Import Merchants

Bulk-onboard sub-merchants: for each entry, creates a new Khaime account if the email doesn't exist yet, or links the existing account if it does. Combines what [Create Merchant](/api-reference/marketplace/create-merchant) and [Link Merchant](/api-reference/marketplace/link-merchant) do individually, per row.

<Warning>
  This endpoint **always returns `201`**, even if every single entry fails. There is no top-level error status for partial or total per-entry failure — you must inspect `data.summary.failed` / `data.results.failed` to know what actually happened. Don't treat a `201` as "all merchants imported successfully."
</Warning>

## Request Body

<ParamField body="merchants" type="array" required>
  Non-empty array, **maximum 100 entries per request**.

  <Expandable title="Merchant entry fields">
    <ParamField body="business_email" type="string" required>
      Required for every entry. If missing or not a string, that entry is recorded in `results.failed` — it does not fail the whole request.
    </ParamField>

    <ParamField body="business_name" type="string">
      Required **only when no existing Khaime account matches `business_email`** (i.e. this entry will create a new account). Omit it when linking an existing account.
    </ParamField>

    <ParamField body="business_phone" type="string">
      Optional, used only on account creation.
    </ParamField>

    <ParamField body="business_country" type="string">
      Optional, used only on account creation.
    </ParamField>

    <ParamField body="commission_rate" type="number">
      Optional decimal between `0` and `1` for this entry. Same inheritance behavior as [Link Merchant](/api-reference/marketplace/link-merchant) when omitted.
    </ParamField>
  </Expandable>
</ParamField>

## Response

```json theme={null}
{
  "success": true,
  "message": "Import complete: 1 created, 1 linked, 0 skipped, 1 failed",
  "data": {
    "summary": { "total": 3, "created": 1, "linked": 1, "skipped": 0, "failed": 1, "succeeded": 2 },
    "results": {
      "created": [
        {
          "email": "new@biz.com",
          "merchant_id": 900,
          "business_name": "New Biz",
          "subdomain": "new-biz",
          "temporary_password": "a1b2c3d4e5f6a1b2c3d4e5f6"
        }
      ],
      "linked": [
        { "email": "existing@biz.com", "merchant_id": 55, "business_name": "Existing Biz", "action": "linked" }
      ],
      "skipped": [
        { "email": "already-active@biz.com", "merchant_id": 33, "business_name": "Already Active Biz", "reason": "Already linked and active" }
      ],
      "failed": [
        { "email": "bad@biz.com", "reason": "commission_rate must be a decimal between 0 and 1" }
      ]
    }
  }
}
```

<Warning>
  **`temporary_password` is returned in plaintext** for every newly created account. This is the account's real login password — treat the response as sensitive, don't log it in plaintext analytics or client-visible logs, and prompt the merchant to change it on first login.
</Warning>

### `linked` entries: `action` is `"linked"` or `"reactivated"`

An entry lands in `results.linked` in two different situations, distinguished by `action`:

* `"linked"` — an existing Khaime account with no prior relationship to your marketplace was linked for the first time.
* `"reactivated"` — the account had a previously **suspended** relationship with your marketplace, now reactivated.

An entry with an existing **active** relationship is not re-linked at all — it goes to `results.skipped` instead (see below), not `results.linked`.

### `skipped` entries

An entry lands here only for one reason today: `reason: "Already linked and active"` — the email already has an active relationship in your marketplace, so nothing changed.

### Per-entry failure reasons

Each item in `results.failed` has a `reason` string, one of:

* `"business_email is required"` — missing or non-string email
* `"commission_rate must be a decimal between 0 and 1"`
* `"Cannot link your own account as a sub-merchant"` — entry's email matches your own operator account
* `"business_name is required when creating a new account (no existing Khaime account found)"`
* any other caught exception message (generic, not enumerable)

## Error Codes

| Status | Error Code               | Cause                                                                                                               |
| ------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `403`  | `AUTH_PERMISSION_DENIED` | Your business isn't a marketplace operator.                                                                         |
| `400`  | `VALIDATION_FAILED`      | `merchants` missing, not an array, empty, or exceeds 100 entries.                                                   |
| `400`  | `INTERNAL_ERROR`         | Unhandled top-level error (individual entry failures do **not** trigger this — see per-entry `failed` array above). |

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.khaime.com/api/v1/partner/marketplace/merchants/import \
    -H "X-API-Key: pk_sandbox_your_key" \
    -H "Content-Type: application/json" \
    -d '{
      "merchants": [
        { "business_email": "new@biz.com", "business_name": "New Biz", "commission_rate": 0.1 },
        { "business_email": "existing@biz.com" }
      ]
    }'
  ```
</RequestExample>
