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

# Store and Coins

> Cativa's internal economy: coins earned through engagement and spent on store items, with an order lifecycle that hooks into external fulfillment.

<Note>
  Coins and the store are the **gamification-with-real-value** layer. Users accumulate coins by participating in the community and spend them on items in a store. What sets Cativa apart is that each **order has a lifecycle** you connect to your own fulfillment (ship a physical gift, release a coupon, trigger an integration).
</Note>

## The two sides

```
COINS (Wallets)                           STORE (Store)
user wallet             ----spent on---->  store items
balance + history                          order

Earning coins:                            Order lifecycle:
- community engagement                     created ----> approve / reject
- credited via admin/integration                   ----> fulfill / refund
```

**Coins** are the internal economy. Users earn coins through engagement, and you can also credit balance via admin or an integration (for example, a bonus for an external purchase). **The store** exchanges that balance for items. Each redemption becomes an **order**, and the order moves through a lifecycle that is your integration hook for fulfillment.

Think of coins like the tickets at an amusement park: visitors earn tickets by playing and trade them for a prize at the counter. The **order** is the counter receipt; approving it, handing over the prize, and (if it was out of stock) returning the tickets are the steps you control.

## Base URL and authentication

All routes live on the **Cativa API**:

```
https://apis.cativalab.digital/tenant/api/v2
```

Authenticate with your API Key in the header:

```
Authorization: Bearer cativa_live_...
```

<Warning>
  Never expose your API Key in the frontend or commit it to the repository. Use `YOUR_API_KEY` as a placeholder and inject the real value through an environment variable.
</Warning>

## Coins (Wallets)

Balance and history live in the user's wallet.

| Route                              | What it does                              |
| ---------------------------------- | ----------------------------------------- |
| `GET /monetization/wallet/coins`   | User's coin balance                       |
| `GET /monetization/wallet/history` | Statement (history of earnings and spend) |

On the admin side, you credit balance and query any user's wallet (by id or by email). See the endpoints and exact fields in the API Reference, tag **Wallets**.

### Check the user's balance

<CodeGroup>
  ```bash cURL theme={null}
  curl https://apis.cativalab.digital/tenant/api/v2/monetization/wallet/coins \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```js Node theme={null}
  const res = await fetch(
    "https://apis.cativalab.digital/tenant/api/v2/monetization/wallet/coins",
    {
      headers: { Authorization: `Bearer ${process.env.YOUR_API_KEY}` },
    }
  );

  const wallet = await res.json();
  ```
</CodeGroup>

Illustrative response (the authoritative schema lives in the API Reference, tag **Wallets**). `balance` is the user's coin balance, in whole units:

```json theme={null}
{
  "balance": 1250
}
```

<Note>
  The exact response shape (balance, currency, and history field names) lives in the API Reference. Check the **Wallets** and **Store** tags instead of assuming the shape here.
</Note>

## Store

Users browse stores, view items, and redeem them with coins.

| Route                                               | What it does               |
| --------------------------------------------------- | -------------------------- |
| `GET /monetization/stores`                          | List stores                |
| `GET /monetization/stores/{storeId}/items`          | Items in a store           |
| `GET /monetization/stores/items/{itemId}`           | Item detail                |
| `POST /monetization/stores/items/{itemId}/purchase` | Redeem the item with coins |
| `GET /monetization/stores/my-orders`                | The user's orders          |

The IDs (`storeId`, `itemId`, `orderId`) are **ULIDs**.

On the admin side, you manage stores and items and operate orders:

* `POST /admin/monetization/stores` · `PUT` / `DELETE /admin/monetization/stores/{storeId}`
* `POST /admin/monetization/stores/{storeId}/items` · `PUT` / `DELETE /admin/monetization/stores/items/{itemId}`
* `GET /admin/monetization/stores/orders` · `GET /admin/monetization/stores/orders/{orderId}`

## The order lifecycle

When a user redeems an item, an order is created. That order moves through a lifecycle, and each transition is an admin action:

```
created ----> approve  ----> fulfill
        \---> reject         \---> refund
```

* **approve / reject**: you validate the redemption (stock, eligibility, anti-fraud) and approve or decline it.
* **fulfill**: you mark the order as delivered. This is where **external fulfillment** happens — ship the physical gift, generate the coupon, call your logistics integration.
* **refund**: return the coins to the user when the item can't be delivered.

The admin order actions are:

* `POST /admin/monetization/stores/orders/{orderId}/approve`
* `POST /admin/monetization/stores/orders/{orderId}/reject`
* `POST /admin/monetization/stores/orders/{orderId}/fulfill`
* `POST /admin/monetization/stores/orders/{orderId}/refund`

The typical flow of a redemption, from the user's click to closing the loop:

<Steps>
  <Step title="User redeems">
    `POST /monetization/stores/items/{itemId}/purchase` debits the coins and creates the order in its initial state.
  </Step>

  <Step title="You validate and approve">
    `POST /admin/monetization/stores/orders/{orderId}/approve` (or `reject`) after checking stock, eligibility and anti-fraud.
  </Step>

  <Step title="You deliver and fulfill">
    Run your external fulfillment (ship the gift, generate the coupon) and close it with `POST .../fulfill`.
  </Step>

  <Step title="If something fails, refund">
    `POST .../refund` returns the coins to the user when the item can't be delivered.
  </Step>
</Steps>

<Tip>
  Treat `fulfill` as your operation's webhook. When you approve an order, kick off your delivery process; when the external delivery completes, call `fulfill` to close the loop. If delivery fails, use `refund` to return the coins.
</Tip>

### Approve and fulfill an order

<CodeGroup>
  ```bash cURL theme={null}
  # 1. approve the redemption
  curl -X POST \
    https://apis.cativalab.digital/tenant/api/v2/admin/monetization/stores/orders/01J8Z9K3M4N5P6Q7R8S9T0V1W2/approve \
    -H "Authorization: Bearer YOUR_API_KEY"

  # 2. after delivering the item externally, mark it fulfilled
  curl -X POST \
    https://apis.cativalab.digital/tenant/api/v2/admin/monetization/stores/orders/01J8Z9K3M4N5P6Q7R8S9T0V1W2/fulfill \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```js Node theme={null}
  const base =
    "https://apis.cativalab.digital/tenant/api/v2/admin/monetization/stores/orders";
  const orderId = "01J8Z9K3M4N5P6Q7R8S9T0V1W2";
  const headers = { Authorization: `Bearer ${process.env.YOUR_API_KEY}` };

  // 1. approve the redemption
  await fetch(`${base}/${orderId}/approve`, { method: "POST", headers });

  // 2. after delivering the item externally, mark it fulfilled
  await fetch(`${base}/${orderId}/fulfill`, { method: "POST", headers });
  ```
</CodeGroup>

Illustrative order response after `approve` (the authoritative schema lives in the API Reference, tag **Store**). `status` reflects the lifecycle step:

```json theme={null}
{
  "orderId": "01J8Z9K3M4N5P6Q7R8S9T0V1W2",
  "status": "approved",
  "itemId": "01J8ITEM4567890ABCDEFGHJKM",
  "userId": "01HQ0USER1234567890ABCDEF",
  "coinsSpent": 500,
  "createdAt": "2026-07-10T14:00:00Z"
}
```

<Note>
  Each route's response fields (order status, amounts, timestamps) live in the API Reference, tags **Store** and **Wallets**. Don't assume the shape from the examples above.
</Note>

## Common errors and questions

<AccordionGroup>
  <Accordion title="The redemption failed with insufficient balance">
    `purchase` only creates the order if the user has enough coins for the item. Without balance, the call is rejected and no order is created. Check `GET /monetization/wallet/coins` first, or credit balance through the admin endpoint (tag **Wallets**) if your program's rules allow it.
  </Accordion>

  <Accordion title="The order is stuck at approved and never got delivered">
    `approve` only validates the redemption; it does not deliver anything on its own. Delivery is **your** external fulfillment, and you are the one who calls `fulfill` when it completes. An approved-but-never-fulfilled order stays open on purpose, waiting for your operation to close the loop.
  </Accordion>

  <Accordion title="Coins were debited but the item couldn't be delivered">
    Use `refund`. It returns the order's coins to the user's wallet. It's the correct exit when stock ran out or the logistics integration failed after the debit.
  </Accordion>

  <Accordion title="I called approve twice, did anything double up?">
    Order transitions are idempotent per state: re-applying `approve` to an already-approved order does not create a second order or debit again. That makes it safe to retry the admin actions in jobs.
  </Accordion>

  <Accordion title="I want to unlock access to a group, not deliver a physical item">
    The store delivers **items**; it is not the access mechanism. To unlock a group, course or space, use **badge as permission** (see [badges as permissions](/en/concepts/badges-as-permissions)). Coins and access are separate layers.
  </Accordion>
</AccordionGroup>

## How it connects

* To **credit coins** for an external action (purchase, referral, gift), use the admin credit endpoints by id or email (tag **Wallets**).
* To **grant access** instead of delivering a physical item, the mechanism is different: see [badges as permissions](/en/concepts/badges-as-permissions).
* To understand **who** owns the wallet and the order, see [identity and users](/en/concepts/identity-and-users).
