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

# Reselling

> Sell another store's products as your own, drawing their stock at the moment you make a sale.

## Overview

Reselling lets you list another Komerza store's products in your own store. When one of your customers buys, Komerza draws a unit from the supplier's stock, charges it to a balance you hold with them, and hands the delivery straight to your customer.

You never hold their stock, and you never front the money for units you have not sold.

<Note>
  If your own store is on Komerza, none of this page applies to you. Your draws
  are served internally and there is nothing to configure - set it all up from
  **Reselling** in your dashboard instead.
</Note>

This guide is for **off-platform resellers**: you sell somewhere other than Komerza.

## Getting approved

Every supplier decides how people join, and you will meet one of three:

| Mode            | What happens                                     |
| --------------- | ------------------------------------------------ |
| **Open**        | You are approved the moment you join.            |
| **Application** | You fill in their form and wait for a decision.  |
| **Invite only** | Nothing is shown until they invite you by email. |

An invite-only programme is not discoverable. Asking about one answers exactly as it would for a store with no programme at all, so there is nothing to find by guessing.

### Application forms

Suppliers taking applications can ask their own questions - short answers, long ones, dropdowns, checkboxes, numbers, links. You answer them once, when you apply.

What you answered is stored with the wording it was asked under, so a supplier who later rewords the form does not change what you appear to have been asked.

### Deposits

A supplier may ask for money before they will approve you. Two settings do quite different things, and the panel tells you which you are looking at:

* A **required deposit** blocks approval outright. Nothing happens until it is paid.
* An **automatic approval amount** is optional. Reach it and you are approved on the spot instead of waiting; ignore it and your application still sits in the queue like any other.

Money you pay in becomes your balance with that supplier, which is what stock is bought from. If they turn you down, it stays yours - it remains as store credit, and they can refund it on request.

## Your shop

Suppliers can publish a list of who resells for them. If you sell on Komerza you are named by your own store; if you sell anywhere else, there is nothing to name you by until you say so.

Set a shop name, a link and a logo under **Reselling** in the supplier's customer dashboard, and that is what appears wherever they list you. Leave it and you appear unnamed.

## Two ways to get stock

Both start the same way: get approved by the supplier's reseller programme, and fund a balance with them. Stock is paid for out of that balance either way.

<CardGroup cols={2}>
  <Card title="Buy up front" icon="box">
    Buy a quantity now and download it as a text file. Nothing to build - the
    units are yours to sell wherever you like.
  </Card>

  <Card title="Draw per sale" icon="bolt">
    Your storefront calls Komerza at the moment it makes a sale, and gets a unit
    back. Needs a store that can call out mid-checkout.
  </Card>
</CardGroup>

You can use both, and most people start with the first.

## Buying up front

From the supplier's customer dashboard, under **Reselling**: pick a product, choose a quantity, and confirm. The cost comes out of your balance and the units come straight back, downloadable as a text file with one unit per line.

Nothing about this needs an integration. If your own shop is a Discord bot, a spreadsheet, or a marketplace listing, this is the whole thing.

<Note>
  Suppliers can turn this off, in which case every sale has to draw at the time
  through a delivery URL. It is on by default.
</Note>

Two limits worth knowing:

* **Text-delivered products only.** A file-delivered product cannot be handed over as a downloadable unit, though it still sells fine drawn per sale.
* **The supplier's delivery has to answer per unit.** If it returns one response for the whole order, one unit arrives and the rest is refunded to your balance. Suppliers wanting to sell in bulk should return an `items` array - see [Dynamic Delivery](/guides/dynamic-delivery#honouring-quantity).

If fewer units arrive than you paid for, the difference goes back to your balance automatically. You are never charged for stock that did not turn up.

## Drawing per sale

The rest of this page covers the other route: your store calls a delivery URL when it makes a sale, and Komerza draws a unit from the supplier at that moment.

1. **You generate a delivery URL** and paste it into your own product's delivery configuration.
2. **A customer buys** from you. Your store calls the delivery URL, Komerza draws a unit from the supplier, and returns it.

## Your delivery URL

Generate it from the supplier's customer dashboard, under **Reselling**, then take the URL for the product you want from the catalogue on the same page - the **Copy ID** button beside each product gives you the last part.

```
https://m-api.komerza.com/reseller/delivery/{token}/{product-id}
```

Two parts, both from that page:

<ParamField path="token" type="string" required>
  Identifies you, and authorises the draw. Shown once when you generate it.
</ParamField>

<ParamField path="product-id" type="string" required>
  Which of the supplier's products to draw. Copy it from the catalogue. A
  product with several variants asks you which one - the price and stock differ
  per variant, so the id has to name one.
</ParamField>

<Warning>
  **The URL is the credential.** Anyone who has it can draw stock and spend your
  balance with that supplier. Treat it like a password: store it where you keep
  secrets, never commit it, and never paste it into a support ticket or a
  screenshot.
</Warning>

Komerza keeps only a hash of the token, so it is shown once and cannot be looked up again. If you lose it or it leaks, generate a new one - the previous URL stops working immediately.

### Why there is no signature

Delivery calls are not signed. Your store signs its outbound requests with its own secret, or does not sign at all, and Komerza has no way to verify a signature it did not issue the key for. Requiring one would mean nobody could integrate.

The unguessable token takes its place. That is a deliberate trade: it is simpler to integrate and weaker than a signature, which is why the token is 256 bits, is never returned twice, and can be replaced at any time.

## The request

A `POST` to that URL. **The body is optional** - the product is already in the URL, so there is nothing you have to look up or map.

```json theme={null}
{
  "lineItemId": "ORD-1042-1",
  "quantity": 2
}
```

<ParamField body="lineItemId" type="string">
  Your own reference for this sale - an order number, a line id, a cart
  reference. Any string; it does not have to be a Komerza id. This is the
  idempotency key, so sending it is strongly recommended - see
  [Retries](#retries). Also accepted as `orderReference`, `orderId` or
  `reference`.
</ParamField>

<ParamField body="quantity" type="integer" default="1">
  How many units were sold. The response contains one entry per unit.
</ParamField>

Anything else you send is ignored, so if your platform already posts a dynamic-delivery payload you can point it at this URL unchanged - it will find the two fields it needs and skip the rest.

<Note>
  If your storefront can only call one URL for everything, there is an older
  route that takes the product from the body instead. It requires a Komerza
  variant of your own mapped to the supplier's, so it only suits resellers who
  also sell on Komerza. Ask the supplier if you need it.
</Note>

## The response

`200 OK` with one entry per unit:

```json theme={null}
{
  "items": ["LICENSE-KEY-ABC123", "LICENSE-KEY-DEF456"],
  "sourceOrderId": "5f3a8b2c-1d4e-5f6a-7b8c-9d0e1f2a3b4c",
  "cost": 14.0,
  "currency": "USD",
  "sampled": 0
}
```

<ResponseField name="items" type="string[]">
  The delivered units, one entry per unit sold. Hand these to your customer.
</ResponseField>

<ResponseField name="sourceOrderId" type="string">
  The order raised on the supplier's store. Quote it if you need to chase them
  about a delivery.
</ResponseField>

<ResponseField name="cost" type="number">
  What was charged to your balance, in the supplier's currency.
</ResponseField>

<ResponseField name="sampled" type="integer">
  Units the supplier gave you free as a sample. These cost nothing.
</ResponseField>

The `items` shape is the same one Komerza's dynamic delivery accepts, so a Komerza store consuming this needs no translation.

<Warning>
  **`cost` is worked out at the moment of the draw, not when you set your
  prices.** If the supplier raises theirs, the next sale costs you more and
  nothing stops it - check `cost` against what you charged, or buy up front,
  where you agree the price before you pay it.
</Warning>

## Retries

`lineItemId` is the idempotency key. Calling again with the same one returns the units already drawn for it rather than drawing more - so a retry after a timeout is safe and cannot double-charge your balance.

Use a stable reference from your own order. A fresh one on each attempt reads as a separate sale and draws again, and **omitting it entirely means every call is a new purchase** - which is why it is the one field worth sending.

Your references are yours alone. Two resellers both sending `1` are two different draws; nobody ever receives someone else's stock by picking the same reference.

## Failures

<ResponseField name="402 Payment Required" type="error">
  The draw was refused. The body carries a short reason.
</ResponseField>

Responses are deliberately terse: the caller is a storefront, and the detail of *why* a draw failed is not something to expose there. The full reason is in your reseller panel on the supplier's store.

Common causes:

<AccordionGroup>
  <Accordion title="Your balance is too low">
    Top it up from the supplier's customer dashboard. Draws are charged at the
    moment of sale, so a balance that runs out mid-day stops deliveries.
  </Accordion>

  <Accordion title="The supplier is out of stock">
    Nothing you can fix. Consider buying stock up front if they allow it, which
    also protects you from them running out.
  </Accordion>

  <Accordion title="Your access was revoked">
    The supplier withdrew it. Stock you already bought outright is still yours.
  </Accordion>

  <Accordion title="The product is no longer offered">
    They removed it from their reseller catalogue, or paused it. The same answer
    covers a URL naming a product this supplier does not offer you at all -
    which the catalogue is deliberately not going to confirm either way.
  </Accordion>
</AccordionGroup>

## Chains

A product can be resold through more than one store, but not indefinitely - a draw is refused once it has passed through **two** stores.

Between Komerza stores that is counted for you: Komerza walks the chain of listings above the product and refuses one that runs deeper than two stores, or that loops back on itself.

Off-platform there is no chain to walk - Komerza cannot see who called you - so the count has to arrive with the request:

```
X-Komerza-Resell-Depth: 1
```

Send it only when you are forwarding a draw you received: take the number you were sent and add one. A request without the header counts as the first hop, which is what an ordinary sale of your own is.

<Warning>
  **Komerza does not add this header for you**, including on a draw it forwards
  to another store, so a chain of off-platform shops is capped only if each one
  counts. Passing a header through unchanged is not counting - the number has to
  go up at every hop, or the ceiling is never reached.
</Warning>

## Volume pricing

Suppliers can set price breaks for buying in quantity. They apply to both routes, but they are far easier to reach by buying up front, since a per-sale draw is usually for one unit.

The highest threshold your quantity clears wins, and terms set on a specific product beat catalogue-wide ones. A price break worse than the everyday reseller price is ignored rather than charged, so a supplier's typo can never make buying in bulk cost more than buying one at a time.

Volume pricing asks *how many of this product*. Two other things ask *how much altogether*, and they are what a spread across a catalogue actually earns.

## Basket discounts

A supplier can take a percentage off any basket that reaches a size, whatever it is made of. A hundred weekly keys and a hundred yearly ones are the same number and nothing like the same order, so these are measured in **value**, not units.

The size is measured at list price, before anything else comes off - qualifying cannot lower a basket's value and disqualify it again. Where several thresholds apply, the largest wins.

## Bundles

A bundle is a basket the supplier composed and priced as one thing: so many of this, so many of that, one figure at the end.

```
100 × 7-Day Key     $499.00
 30 × 30-Day Key    $509.70
 25 × 90-Day Key    $999.75
─────────────────────────────
Retail value      $2,008.45
45% off
You pay           $1,104.65
```

Buying one runs the same purchase as buying its lines yourself, so stock, delivery and refunds behave exactly as they always do. Three things are worth knowing:

* **It can never cost more than buying the lines separately.** If your own terms already beat the bundle, you pay yours.
* **A bundle is bought as composed.** Quantities are the supplier's, not yours - assembling your own basket is what basket discounts are for.
* **If a product in it is no longer offered, the whole bundle stops being buyable** rather than quietly shrinking. You are told which line is short.

A supplier can aim a bundle at particular resellers, cap how many times you may take it, or run it between two dates. One aimed at somebody else is not listed to you, and cannot be bought by guessing its id.
