# Getting started (https://docs.loybox.com.ar/en/api-reference/primeros-pasos)



This page is the complete integration, end to end. If you are here to implement
and want to read a single page before writing code, this is the one.

There are **two paths** and they are not exclusive: almost every integration
starts with the first and adds the second when they want the member to see their
own points.

| Path                                                         | What it solves                                                       | Credential                                                            |
| ------------------------------------------------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [From your server](#camino-1-sumar-puntos-desde-tu-servidor) | Making purchases earn points and codes get redeemed at the sale      | [API key](https://docs.loybox.com.ar/api-reference/credenciales#api-key-del-comercio)           |
| [From your frontend](#camino-2-el-club-en-tu-frontend)       | Letting the member see their points, buy rewards and show their code | [End-user token](https://docs.loybox.com.ar/api-reference/credenciales#token-del-usuario-final) |

## Before you start
You need two things, and we give you both: write to us at
[hola@loybox.com.ar](mailto:hola@loybox.com.ar).

<Fields>
  <Field name="LOYBOX_API_KEY" type="secret" required="true">
    The commerce API key. It goes on your server only.
  </Field>

  <Field name="commerce_id" type="public" required="true">
    Your commerce id. This is what travels in the `X-Commerce-Id` header and it
    can live in the frontend.
  </Field>
</Fields>

From here on, the examples use the
[reference's conventions](https://docs.loybox.com.ar/api-reference#los-ejemplos): `$LOYBOX_API_KEY` for the
API key, `$ACCESS_TOKEN` for the end-user token and `87` as the `commerce_id`.

## Path 1: earning points from your server
This is the minimum integration of a loyalty program: a single call, at the point
where your system confirms a sale.

<Steps>
  <Step>
    ### Record the purchase
    At an online checkout you already have the email, so
    [by email](https://docs.loybox.com.ar/api-reference/consumos/crear-por-email) is the short path: it works
    even if the member does not have a Loybox account yet.

    ```bash
    curl -X POST https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/consumptions/email \
      -H "Authorization: Bearer $LOYBOX_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "client_email": "ana@example.com",
        "amount": 1750
      }'
    ```

    At a physical point of sale, where the member gives their number, it is the same
    call [by code](https://docs.loybox.com.ar/api-reference/consumos/crear-por-codigo) with `client_code`.

    <Callout type="warn" title="The amount is an integer">
      `amount` is whole units of the commerce's currency. A purchase of `1,750.50` is
      sent as `1750`.
    </Callout>

    How many points it earns is not decided by your call: it is decided by the
    commerce's configuration. You send the amount and Loybox applies the
    money-per-point rule, double points if they are running, and the tier bonus, in
    that order ([the formula](https://docs.loybox.com.ar/referencia-tecnica#cálculo-de-puntos)).
  </Step>

  <Step>
    ### Show them the balance
    The consumption's response does not say how many points it added. The balance is
    [looked up separately](https://docs.loybox.com.ar/api-reference/clientes/obtener):

    ```bash
    curl https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/clients/12345 \
      -H "Authorization: Bearer $LOYBOX_API_KEY"
    ```

    With this you already have a working program: purchases earn and the member has a
    balance.
  </Step>

  <Step>
    ### Look up the code the member brings
    When a member shows up with a redemption code (their `client_benefit_code`), the
    first thing is to see what it is. Use
    [v2](https://docs.loybox.com.ar/api-reference/beneficios/consultar-codigo-v2), which brings the discount's
    value at the root:

    ```bash
    curl https://loybox-public-api-752998171300.southamerica-west1.run.app/v2/benefits/preview/887766 \
      -H "Authorization: Bearer $LOYBOX_API_KEY"
    ```

    With the response's `type` and `value` you apply the discount in your sale:

    | `type`                | What to do                       |
    | --------------------- | -------------------------------- |
    | `percentage_discount` | Apply the percentage in `value`. |
    | `absolute_discount`   | Subtract the amount in `value`.  |
    | `free_product`        | Add the product in `product`.    |

    A `400` here means the code was already used: do not apply anything.
  </Step>

  <Step>
    ### Redeem it once the sale closed
    [Redemption](https://docs.loybox.com.ar/api-reference/beneficios/canjear) burns the code and there is no
    going back:

    ```bash
    curl -X POST https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/benefits/redeem \
      -H "Authorization: Bearer $LOYBOX_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "client_benefit_code": 887766
      }'
    ```

    <Callout type="warn" title="Order matters">
      Looking up is harmless and can be repeated; redeeming is final. If you redeem
      before closing the sale and the sale falls through, the member lost the reward and
      there is no way to give it back over the API.
    </Callout>
  </Step>
</Steps>

## Path 2: the club in your frontend
Here Loybox works as the loyalty engine under your product: the user signs in with
a code emailed to them and from there sees their points, buys benefits and shows
their codes. All of this can run in the browser.

<Callout type="warn" title="The API key has no place on this path">
  No call on this path carries the API key: it grants access to the data of all your
  members. What travels is the end-user token, which only sees their own data, plus
  the `X-Commerce-Id`, which is not a secret.
</Callout>

<Steps>
  <Step>
    ### Ask for the code
    ```bash
    curl -X POST https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/auth/otp/request \
      -H "X-Commerce-Id: 87" \
      -H "Content-Type: application/json" \
      -d '{
        "email": "ana@example.com"
      }'
    ```

    It always answers `200`, even if that email has no account. In the UI you always
    show the same message ("we sent a code to your email"), because you cannot know
    whether the account existed.
  </Step>

  <Step>
    ### Verify it and store the session
    ```bash
    curl -X POST https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/auth/otp/verify \
      -H "X-Commerce-Id: 87" \
      -H "Content-Type: application/json" \
      -d '{
        "email": "ana@example.com",
        "otp": "418302"
      }'
    ```

    It returns `access` and `refresh`. Store both: the `access` expires in
    `expires_in` seconds and the `refresh` is what
    [renews it](https://docs.loybox.com.ar/api-reference/autenticacion/renovar-token) without asking the user
    for another code. If the email had no account, one is created, and either way the
    user ends up subscribed to your program.
  </Step>

  <Step>
    ### Paint the screen with a single call
    [`GET /v1/me`](https://docs.loybox.com.ar/api-reference/mi-cuenta/obtener) brings the points, the
    commerce's branding and the points about to expire, all at once:

    ```js
    const res = await fetch(
      'https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/me',
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
          'X-Commerce-Id': '87',
        },
      },
    );

    const me = await res.json();
    // me.points -> the big balance on the screen
    // me.commerce -> logo, name and color for the program's branding
    // me.subscribed -> if it comes back false, show the call to join
    ```

    A `401` here means the `access` expired:
    [renew it](https://docs.loybox.com.ar/api-reference/autenticacion/renovar-token) and retry the call.
  </Step>

  <Step>
    ### Show the catalog and buy
    [The catalog](https://docs.loybox.com.ar/api-reference/mi-cuenta/beneficios-disponibles) comes back
    unfiltered by balance: you compare each benefit's `cost` with the user's `points`
    and decide what to show as reachable and what as "you need N more points".

    ```bash
    curl -X POST https://loybox-public-api-752998171300.southamerica-west1.run.app/v1/me/benefits/exchange \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "X-Commerce-Id: 87" \
      -H "Idempotency-Key: 8f14e45f-ea0f-4d1c-9a1b-2c3d4e5f6a7b" \
      -H "Content-Type: application/json" \
      -d '{
        "benefit_id": "b_9f2a"
      }'
    ```

    <Callout title="Buying and redeeming are not the same">
      Buying trades points for a benefit, and the user does it from your frontend.
      Redeeming uses that benefit in the sale, and your server does it with the API key
      ([step 4 of path 1](#camino-1-sumar-puntos-desde-tu-servidor)).
    </Callout>
  </Step>

  <Step>
    ### Show them the code
    The purchase returns a `client_benefit_code`. That number is both the redemption
    code and the coupon code: in an online store it is what the user pastes at
    checkout, and in a physical store it is what they show at the counter.

    Show it large, with a copy button and the `due_date` next to it. The full list of
    the ones they hold is in
    [my benefits](https://docs.loybox.com.ar/api-reference/mi-cuenta/mis-beneficios).
  </Step>
</Steps>

## The full circuit
The two paths close like this, and it is the mental model worth having before
writing code:

```
purchase ─▶ POST /v1/consumptions/email        (your server, API key)
             │
             ▼
          points to the member
             │
             ▼
        POST /v1/me/benefits/exchange          (your frontend, end-user token)
             │
             ▼
       client_benefit_code
             │
             ▼
      GET /v2/benefits/preview/{code}          (your server, API key)
             │
             ▼
        POST /v1/benefits/redeem               (your server, API key)
```

## Before going to production
* The **API key lives on your server only**. If it leaked, write to us and we
  rotate it.
* **Never retry a `400`** blindly: it is the already-used benefit, the expired one
  or points that fall short. Read the `message` and stop.
* **Buying a benefit carries an `Idempotency-Key`**. It is what prevents charging
  the points twice when the network drops.
* A &#x2A;*`401`** in My account is the signal to renew the token, not to sign the user
  out.
* The &#x2A;*`404` from [my tier](https://docs.loybox.com.ar/api-reference/mi-cuenta/nivel)** is the normal case
  for a new member: hide the tiers section, do not show an error.
* **`points_expiration` does not come back `null`** when points do not expire: it
  comes with `mode: "none"`. Check the `mode` before showing the notice.

## If you are implementing with an agent
The API is published in machine format:

* [`/openapi.json`](https://docs.loybox.com.ar/openapi.json): the complete OpenAPI 3.1 specification, with
  all 25 endpoints, the schemas and the two credentials. Good for generating a
  typed client. Its descriptions are in Spanish; the names and schemas are not.
* [`/llms.txt`](https://docs.loybox.com.ar/llms.txt) and [`/llms-full.txt`](https://docs.loybox.com.ar/llms-full.txt): the whole docs
  as text, meant to be handed over as context. These two are per language, so the
  links above are the English ones.
* Any page of the docs as raw Markdown by appending `.md` to the URL, for example
  [`/api-reference/credenciales.md`](https://docs.loybox.com.ar/api-reference/credenciales.md).
