# Commerce and shops

Use Commerce to give a creator, club or church a merch shop. Fans browse products on a storefront, you price their cart with shipping and tax, and an order records what they bought. Your organizers add products, submit them for review and move orders through fulfilment.

## How the pieces fit

| Resource | What it is |
|---|---|
| Storefront | The list of a creator's published products. It hangs off a fanbase or a creator page (a capsule). Both URLs return the same products. |
| Product | Something to sell: `physical`, `digital`, `bundle` or `external`. It has a price, optional shipping and tax, and optional variants with stock. |
| Cart | A priced list of items with shipping and tax. It is priced on request and not saved. |
| Order | A buyer's purchase with a code like `MCH-ABC123DEF4`. It starts `pending` and `unfulfilled`. |
| Fulfilment status | Where the order is for the organizer: `unfulfilled`, `processing`, `fulfilled` or `cancelled`. |

A client uses them in this order:

1. An organizer creates a product. It starts as a `draft`.
2. The organizer submits it. The product moves to `pending_review` and a tenant admin approves or rejects it.
3. An approved product is `published`. A published, public product shows on the storefront.
4. Your app lists the storefront and prices a cart with `POST /v1/merch/cart`.
5. Your app creates the order with the same items and the buyer's details.
6. The organizer works the order from `unfulfilled` to `fulfilled`.

Product `price`, `shipping_fee` and `tax_amount` are set in KES, for example `1500`. Carts and orders return integer cents in fields such as `total_cents`. Shipping and tax are flat amounts set on each product. One cart or order can only hold products from one creator, and a sold-out variant is refused with a `422`.

## What is not available yet

Paying for a merch order is not available through the API today. Creating an order records it as `pending` with its totals and `checkout_url` set to `null`, and nothing marks a merch order `paid`. A refund request records the request on the order. It does not return money. See [what's coming](https://docs.vabu.live/whats-coming.md) for merch checkout.

## What you can call today

### Browse a storefront (no sign-in)

| Method | Path | What it does |
|---|---|---|
| GET | `/v1/public/capsules/{slug}/storefront` | List a creator's published products, 12 to a page. |
| GET | `/v1/public/capsules/{slug}/storefront/products/{product}` | Get one product with its variants. |
| GET | `/v1/public/fanbases/{slug}/storefront` | The same list, by fanbase slug. |
| GET | `/v1/public/fanbases/{slug}/storefront/products/{product}` | The same product, by fanbase slug. |

If the creator also sells somewhere else, the storefront response carries `external_storefront_url`. A fanbase that is hidden answers `404`.

### Cart and orders

| Method | Path | What it does |
|---|---|---|
| POST | `/v1/merch/cart` | Price a cart. Returns line items, `subtotal_cents`, `shipping_cents`, `tax_cents` and `total_cents`. No sign-in. |
| POST | `/v1/merch/orders` | Create an order from the same items and the buyer's `customer` details. No sign-in. |
| GET | `/v1/merch/orders/{code}` | Get an order and its status by code. No sign-in. |
| POST | `/v1/merch/orders/{code}/refund-request` | Record a refund request, with an optional `reason`. Needs a signed-in user. |

Here is a cart priced for two of one product:

```sh
curl -X POST "https://api.vabu.live/v1/merch/cart" \
  -H "X-Tenant-Code: your_tenant_code" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"product_id":"550e8400-e29b-41d4-a716-446655440000","quantity":2}],"customer":{"name":"Amina Wairimu"}}'
```

### Organizer: products and orders

| Method | Path | What it does |
|---|---|---|
| GET, POST | `/v1/organizer/merch/products` | List products with a count for each status, or create a draft. |
| GET, PATCH | `/v1/organizer/merch/products/{product}` | Read or update a product. |
| POST | `/v1/organizer/merch/products/{product}/publish` | Submit a product for tenant review. |
| POST | `/v1/organizer/merch/products/{product}/media` | Upload an image, up to 10 MB, to the `poster` or `gallery` collection. |
| GET | `/v1/organizer/merch/orders` | List your orders. Filter by `status`. |
| PATCH | `/v1/organizer/merch/orders/{order}` | Set the fulfilment status of an order. |

The full parameters for each call are in the [API reference](https://docs.vabu.live/api.md).

## Calling these endpoints

The storefront, cart and order routes take only `X-Tenant-Code`. The refund request needs a signed-in user token (`Authorization: Bearer ...`, a Vabu ID or Payd ID token) plus `X-Tenant-Code`. Every `/v1/organizer/*` route takes that same token and header, in live mode, and accepts an optional `X-Organization-Id` header to pick which organization you act for. Creating or changing products needs the Owner, Admin or Editor role. Test keys and publishable keys are refused on these routes today. See [which credentials each endpoint takes](https://docs.vabu.live/concepts/keys-and-scopes.md#which-credentials-each-endpoint-takes). For paging and error shapes, see [pagination](https://docs.vabu.live/concepts/pagination.md) and [errors](https://docs.vabu.live/concepts/errors.md).

## Related

- [Fanbases](https://docs.vabu.live/products/fanbases.md) for the community a storefront belongs to.
- [Payments](https://docs.vabu.live/products/payments.md) for how checkout works on events today.
- [How the products work together](https://docs.vabu.live/products/how-products-work-together.md) for how the products connect.
- [What's coming](https://docs.vabu.live/whats-coming.md) for merch checkout.
