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

# GET /v1/loyalty/programs

> List the loyalty programs of your company, newest first, with the rules that govern each one.

Lists the loyalty programs of your company. This is the starting point for everything else: a membership, a template, and a ledger movement all hang off a program id.

A program is one of three kinds — `points`, `stamps`, or `tiers` — and only the matching entry inside `rules` is populated.

## Endpoint

```
GET https://api.keebai.com/v1/loyalty/programs
```

## Required scope

`loyalty:read`

## Headers

| Header          | Required | Value                    |
| --------------- | -------- | ------------------------ |
| `Authorization` | Yes      | `Bearer kbai_pk_<token>` |

## Query parameters

| Parameter | Type      | Default | Description                                 |
| --------- | --------- | ------- | ------------------------------------------- |
| `status`  | `string`  | —       | Filter by `draft`, `active`, or `archived`. |
| `type`    | `string`  | —       | Filter by `points`, `stamps`, or `tiers`.   |
| `limit`   | `integer` | `50`    | Records per page, 1–200.                    |
| `offset`  | `integer` | `0`     | Records to skip.                            |

## Example request

<CodeGroup>
  ```bash curl theme={null}
  curl "https://api.keebai.com/v1/loyalty/programs?status=active" \
    -H "Authorization: Bearer kbai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  ```

  ```js JavaScript theme={null}
  const params = new URLSearchParams({ status: "active" });
  const response = await fetch(
    `https://api.keebai.com/v1/loyalty/programs?${params}`,
    { headers: { Authorization: `Bearer ${process.env.KEEBAI_API_TOKEN}` } },
  );
  const { data, total } = await response.json();
  ```

  ```python Python theme={null}
  import os, requests

  resp = requests.get(
      "https://api.keebai.com/v1/loyalty/programs",
      headers={"Authorization": f"Bearer {os.environ['KEEBAI_API_TOKEN']}"},
      params={"status": "active"},
      timeout=10,
  )
  resp.raise_for_status()
  programs = resp.json()["data"]
  ```
</CodeGroup>

## Response

### 200 OK

```json theme={null}
{
  "data": [
    {
      "_id": "6650a1b2c3d4e5f6a7b8c9d0",
      "name": "Coffee Club",
      "type": "stamps",
      "status": "active",
      "description": "Ten stamps, one free coffee",
      "rules": {
        "stamps": {
          "target": 10,
          "reward": "A free coffee",
          "reset_on_redeem": true
        }
      },
      "created_at": "2026-01-05T12:00:00.000Z",
      "updated_at": "2026-02-01T09:30:00.000Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}
```

### 401 Unauthorized

Missing, invalid, revoked, or expired token.

### 403 Forbidden

The token does not have the `loyalty:read` scope.

### 502 Bad Gateway

The loyalty service is unreachable.

## Operational notes

* **Only one `rules` variant is present.** A `stamps` program carries `rules.stamps` and nothing else; the other keys are absent, not empty objects. Switch on `type` rather than probing for keys.
* **Reads span the whole company.** Loyalty has no notion of a project, so this returns every program in your company regardless of which project the token belongs to.
* **Programs are created in the portal.** There is no `POST` here — the API reads program configuration, it does not author it.
* **`archived` programs still list.** Filter by `status=active` if you only want the ones currently running.


## OpenAPI

````yaml GET /v1/loyalty/programs
openapi: 3.0.0
info:
  title: Keebai Public API
  description: Superficie pública REST autenticada con Personal Access Tokens (PAT).
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.keebai.com
    description: Production
security: []
tags: []
paths:
  /v1/loyalty/programs:
    get:
      tags:
        - loyalty
      summary: Listar programas de fidelidad
      description: >-
        Devuelve los programas de la company del token, del más nuevo al más
        viejo. El campo rules solo trae poblada la variante que corresponde al
        type del programa.
      operationId: PublicLoyaltyController_listPrograms
      parameters:
        - name: limit
          required: false
          in: query
          schema:
            minimum: 1
            maximum: 200
            default: 50
            type: number
        - name: offset
          required: false
          in: query
          schema:
            minimum: 0
            default: 0
            type: number
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - draft
              - active
              - archived
        - name: type
          required: false
          in: query
          schema:
            type: string
            enum:
              - points
              - stamps
              - tiers
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicProgramListResponseDto'
      security:
        - PAT: []
components:
  schemas:
    PublicProgramListResponseDto:
      type: object
      properties:
        total:
          type: number
        limit:
          type: number
        offset:
          type: number
        data:
          type: array
          items:
            $ref: '#/components/schemas/PublicProgramDto'
      required:
        - total
        - limit
        - offset
        - data
    PublicProgramDto:
      type: object
      properties:
        _id:
          type: string
        name:
          type: string
          example: Club Cafetería
        type:
          type: string
          enum:
            - points
            - stamps
            - tiers
        status:
          type: string
          enum:
            - draft
            - active
            - archived
        description:
          type: string
          example: Programa de sellos de la cafetería
        rules:
          description: Solo viene poblada la variante que corresponde al type
          allOf:
            - $ref: '#/components/schemas/PublicProgramRulesDto'
        created_at:
          type: string
        updated_at:
          type: string
      required:
        - _id
        - name
        - type
        - status
        - description
        - rules
        - created_at
        - updated_at
    PublicProgramRulesDto:
      type: object
      properties:
        points:
          $ref: '#/components/schemas/PublicPointsRulesDto'
        stamps:
          $ref: '#/components/schemas/PublicStampsRulesDto'
        tiers:
          $ref: '#/components/schemas/PublicTiersRulesDto'
    PublicPointsRulesDto:
      type: object
      properties:
        points_per_currency_unit:
          type: number
          description: Cuántos puntos otorga cada unidad de moneda gastada
          example: 1
        expiration_days:
          type: number
          description: >-
            Días desde la inscripción tras los cuales el saldo se lee 0. Cero
            significa sin vencimiento
          example: 0
      required:
        - points_per_currency_unit
        - expiration_days
    PublicStampsRulesDto:
      type: object
      properties:
        target:
          type: number
          description: Sellos necesarios para el premio
          example: 10
        reward:
          type: string
          description: Descripción libre del premio. No es una entidad, es texto
          example: Un café gratis
        reset_on_redeem:
          type: boolean
          description: Si los sellos vuelven a cero al canjear
      required:
        - target
        - reward
        - reset_on_redeem
    PublicTiersRulesDto:
      type: object
      properties:
        levels:
          type: array
          items:
            $ref: '#/components/schemas/PublicTierLevelDto'
      required:
        - levels
    PublicTierLevelDto:
      type: object
      properties:
        key:
          type: string
          example: gold
        name:
          type: string
          example: Oro
        threshold:
          type: number
          description: Puntos mínimos para alcanzar el nivel
          example: 5000
        benefits:
          example:
            - Envío gratis
            - Acceso anticipado
          type: array
          items:
            type: string
      required:
        - key
        - name
        - threshold
        - benefits
  securitySchemes:
    PAT:
      scheme: bearer
      bearerFormat: kbai_pk_<hex>
      type: http
      description: >-
        Personal Access Token con prefijo `kbai_pk_`. Generar desde el portal
        con permiso `developer.manage_tokens`.

````