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

# Derecho de Bandera de Función

> Restringe características en tu propia aplicación a una compra. Los derechos de bandera de función entregan una capacidad booleana instantáneamente en el pago y la revocan automáticamente en la cancelación.

<Info>
  Un derecho de bandera de función convierte a Dodo Payments en un almacén de banderas de función consciente de la facturación. Adjunta una bandera como `advanced_reports` a un producto, y cada cliente de pago recibe una concesión que tu aplicación puede verificar vía API o mantener sincronizada con webhooks. Sin plataforma externa, sin OAuth, sin paso de entrega: la concesión en sí es la capacidad.
</Info>

## Qué se entrega

Nada sale de Dodo Payments — la concesión **es** el entregable:

* En la compra, se crea la concesión y pasa directamente a `delivered`. No hay fase de `pending`, no hay acción del cliente, y no hay forma de que la entrega falle.
* La concesión lleva una carga útil tipificada `feature`: `{ "feature_type": "boolean", "feature_id": "advanced_reports" }`. Tu aplicación lee `feature_id` para decidir qué desbloquear.
* La cancelación, reembolso o revocación manual mueven la concesión a `revoked`, y tu aplicación ve desaparecer la bandera.

Usos comunes incluyen la restricción de funciones basadas en planes (Pro desbloquea analíticas), capacidades adicionales (una mejora de "acceso API"), y programas de acceso temprano vendidos como compras únicas.

<Note>
  `feature_id` es un identificador elegido por el comerciante, no único en todos los derechos. Dos derechos pueden conferir el mismo `feature_id` — por ejemplo, un plan Pro mensual y uno anual ambos otorgando `advanced_reports`.
</Note>

## Crear una bandera de función

<Steps>
  <Step title="Open Entitlements">
    En tu panel de Dodo Payments, ve a **Derechos** y haz clic en **+** para iniciar un nuevo derecho, luego elige **Banderas de Función**.
  </Step>

  <Step title="Name the flag">
    Dale a la bandera un **Nombre de Presentación** para tu panel, un **ID de Función** que verificará tu aplicación (el panel sugiere uno a partir del nombre), y una **Descripción** para que tu equipo sepa qué controla.

    <Frame caption="Creating a feature flag. The Feature ID is what your application checks; Meta Data attaches limits alongside the flag.">
      <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/create.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=08d8fc2cfee102ff08fd150c76b5fcf9" alt="Formulario de Nueva Bandera de Función con nombre de presentación, ID de función, descripción y entradas de metadatos clave-valor" style={{ maxHeight: '500px', width: 'auto' }} width="1196" height="776" data-path="images/entitlements/feature-flags/create.png" />
    </Frame>
  </Step>

  <Step title="Optionally add metadata">
    Activa **Metadatos** para adjuntar configuración clave-valor — límites, nombres de niveles, cuotas — que se entrega a tu aplicación junto con la bandera. Consulta [Adjuntar límites con metadatos](#attach-limits-with-metadata).
  </Step>

  <Step title="Confirm">
    Haz clic en **Confirmar**. La bandera aparece en tu lista de derechos, lista para adjuntar a productos.

    <Frame caption="The created feature flag. The right pane tracks every customer grant issued from it.">
      <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/list.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=02eedcbbf7ece9f67d375c984c5515b9" alt="Panel de derechos mostrando la bandera de función de Informes Avanzados con su panel de actividad de concesión" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/list.png" />
    </Frame>
  </Step>
</Steps>

## Adjuntar a un producto

Abre un producto (o crea uno), encuentra la tarjeta **Derechos**, y haz clic en **+** para adjuntar derechos existentes. Selecciona tu bandera de función y haz clic en **Hecho**.

<Frame caption="Attaching the feature flag to a product. One product can deliver multiple entitlements.">
  <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/attach-picker.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=da2137873e285cc6ce0ce234fe899ed3" alt="Panel de adjuntos de derechos con la bandera de función de Informes Avanzados seleccionada" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-picker.png" />
</Frame>

La bandera adjunta se muestra en el formulario del producto, y la vista previa del pago la lista bajo **Incluye**.

<Frame caption="The product now includes the feature flag. Every successful purchase or active subscription grants it.">
  <img src="https://mintcdn.com/dodopayments/oS2MTbJuY6MeBjjs/images/entitlements/feature-flags/attach-to-product.png?fit=max&auto=format&n=oS2MTbJuY6MeBjjs&q=85&s=3556181389997edddde9c396d0ce408d" alt="Formulario de producto con la bandera de función de Informes Avanzados adjunta en la tarjeta de Derechos" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-to-product.png" />
</Frame>

## Configuración requerida

| Campo          | Requerido | Descripción                                                                                         |
| -------------- | --------- | --------------------------------------------------------------------------------------------------- |
| `feature_id`   | Sí        | Identificador que verifica tu aplicación, por ejemplo, `advanced_reports`. No único entre derechos. |
| `feature_type` | Sí        | Tipo de capacidad conferida. Solo `boolean` es soportado hoy.                                       |

### Crear vía API

<CodeGroup>
  ```typescript TypeScript theme={null} theme={null}
  import DodoPayments from 'dodopayments';

  const client = new DodoPayments({
    bearerToken: process.env['DODO_PAYMENTS_API_KEY'],
    environment: 'test_mode',
  });

  const entitlement = await client.entitlements.create({
    name: 'Advanced Reports',
    integration_type: 'feature_flag',
    integration_config: {
      feature_type: 'boolean',
      feature_id: 'advanced_reports',
    },
    metadata: {
      tier: 'pro',
      monthly_report_limit: 100,
    },
  });
  ```

  ```python Python theme={null} theme={null}
  client.entitlements.create(
      name="Advanced Reports",
      integration_type="feature_flag",
      integration_config={
          "feature_type": "boolean",
          "feature_id": "advanced_reports",
      },
      metadata={
          "tier": "pro",
          "monthly_report_limit": 100,
      },
  )
  ```

  ```go Go theme={null} theme={null}
  client.Entitlements.New(ctx, dodopayments.EntitlementNewParams{
    Name:            dodopayments.F("Advanced Reports"),
    IntegrationType: dodopayments.F(dodopayments.EntitlementIntegrationTypeFeatureFlag),
    IntegrationConfig: dodopayments.F[dodopayments.IntegrationConfigUnionParam](
      dodopayments.IntegrationConfigFeatureFlagConfigParam{
        FeatureType: dodopayments.F(dodopayments.FeatureTypeBoolean),
        FeatureID:   dodopayments.F("advanced_reports"),
      },
    ),
  })
  ```
</CodeGroup>

***

## Adjuntar límites con metadatos

Una bandera booleana responde "¿tiene este cliente la función?". Los metadatos responden "¿con qué configuración?". Los metadatos de derechos aceptan valores de cadena, entero, número y booleano, y cada concesión toma una **instantánea congelada** de los metadatos del derecho en el momento en que se crea.

Ese comportamiento de instantánea es lo que hace que los metadatos sean seguros para usar en los límites del plan:

* Editar los metadatos del derecho más tarde solo afecta a las **futuras** concesiones. Los clientes mantienen los límites bajo los que compraron.
* La instantánea se devuelve en cada concesión como su campo `metadata`, por lo que una llamada API te da tanto la bandera como su configuración.

Por ejemplo, una bandera `advanced_reports` con `{ "tier": "pro", "monthly_report_limit": 100 }` permite a tu aplicación desbloquear el panel *y* hacer cumplir la cuota de 100 informes sin una segunda consulta. Si más tarde aumentas el límite a 250, los clientes existentes se mantendrán en 100 hasta que reciban una nueva concesión (por ejemplo, después de un cambio de plan).

<Tip>
  Usa metadatos para límites y configuración; usa `feature_id` solo para identidad. Codificar límites en el id (`advanced_reports_100`) fuerza una nueva bandera para cada cambio de límite y rompe las comprobaciones de tu aplicación.
</Tip>

***

## Comprobar las características de un cliente

Lista las concesiones de bandera de función entregadas a un cliente y construye el conjunto de características habilitadas. El endpoint devuelve una fila por concesión en todos los derechos, filtrable por `integration_type` y `status`.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={null}
  const features = new Map<string, Record<string, unknown>>();

  for await (const grant of client.customers.listEntitlementGrants('cus_abc123', {
    integration_type: 'feature_flag',
    status: 'Delivered',
  })) {
    if (grant.feature) {
      features.set(grant.feature.feature_id, grant.metadata ?? {});
    }
  }

  if (features.has('advanced_reports')) {
    const limit = features.get('advanced_reports')?.monthly_report_limit;
    // unlock the dashboard, enforce the limit
  }
  ```

  ```python Python theme={null} theme={null}
  page = client.customers.list_entitlement_grants(
      customer_id="cus_abc123",
      integration_type="feature_flag",
      status="Delivered",
  )

  features = {
      grant.feature.feature_id: grant.metadata
      for grant in page.items
      if grant.feature
  }

  if "advanced_reports" in features:
      limit = features["advanced_reports"].get("monthly_report_limit")
  ```

  ```go Go theme={null} theme={null}
  page, _ := client.Customers.ListEntitlementGrants(
    ctx, "cus_abc123",
    dodopayments.CustomerListEntitlementGrantsParams{
      IntegrationType: dodopayments.F("feature_flag"),
      Status:          dodopayments.F("Delivered"),
    },
  )

  features := map[string]bool{}
  for _, grant := range page.Items {
    if grant.Feature.FeatureID != "" {
      features[grant.Feature.FeatureID] = true
    }
  }
  ```
</CodeGroup>

<Note>
  La carga útil `feature` se povis posts tarjetas `feature_flag` concesiones; es `null` para cada otro tipo de integración. Consulta la referencia de la API [Listar Concesiones de Cliente](/api-reference/entitlements/list-customer-grants) para la forma completa de respuesta.
</Note>

Consultar la API en cada solicitud agrega latencia a tu ruta crítica. Cachea el conjunto de características por cliente con un TTL corto (minutos, no horas), e invalida la caché desde tu manejador de webhooks cuando una concesión cambia de estado: esa combinación mantiene rápidas las comprobaciones y revocaciones casi instantáneas.

***

## Ciclo de vida

Las concesiones de bandera de función siguen el estándar [ciclo de vida de concesión](/features/entitlements/introduction#how-grants-work) con una simplificación: no hay paso de entrega, por lo que las concesiones nunca se sitúan en `pending` y nunca pasan a `failed`.

| Disparador                                           | Efecto                                                                                                      |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| El pago único tiene éxito / suscripción se activa    | Concesión creada con `status: delivered` e `delivered_at` establecido.                                      |
| Suscripción suspendida, cancelada o caducada         | Concesión revocada con la `revocation_reason` coincidente.                                                  |
| Reembolso en un pago único                           | Concesión revocada con `revocation_reason: refund`.                                                         |
| Suscripción se recupera (por ejemplo, cobro exitoso) | La concesión revocada se restaura a `delivered` — mismo `id` de concesión, campos de revocación despejados. |
| Revocación manual de API                             | Concesión revocada con `revocation_reason: manual`. No se restaura automáticamente en la renovación.        |

Las concesiones son idempotentes por derecho y cliente: mientras un cliente tenga una concesión no revocada para una bandera, las compras y renoves repetidas no crean duplicados.

***

## Webhooks

Suscríbete a los [eventos `entitlement_grant.*`](/developer-resources/webhooks/intents/entitlement-grant) para reflejar las banderas en tu propia base de datos en lugar de sondear:

* `entitlement_grant.created` — llega ya `delivered` con la carga útil `feature`. Activa la función.
* `entitlement_grant.delivered` — se activa cuando una concesión previamente revocada se restaura. Re-activa la función.
* `entitlement_grant.revoked` — acceso retirado. Desactiva la función y verifica `revocation_reason` para decidir tu mensajería.

```typescript TypeScript theme={null} theme={null}
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  if (event.type.startsWith('entitlement_grant.') && event.data.feature) {
    const { customer_id, feature } = event.data;
    const enabled = event.type !== 'entitlement_grant.revoked';

    await db.customerFeatures.upsert({
      customerId: customer_id,
      featureId: feature.feature_id,
      enabled,
      config: event.data.metadata ?? {},
    });
  }

  res.sendStatus(200);
});
```

No hay `entitlement_grant.failed` para banderas de función — la entrega ocurre completamente dentro de Dodo Payments y no puede fallar.

***

## Ejemplo: El plan Pro desbloquea informes avanzados

1. **Crea la bandera.** `feature_id: advanced_reports` con metadatos `{ "tier": "pro", "monthly_report_limit": 100 }`.
2. **Adjúntala** a tu producto de suscripción del Plan Pro.
3. **Un cliente se suscribe.** Dodo Payments crea una concesión `delivered` y dispara `entitlement_grant.created`; tu manejador de webhooks habilita `advanced_reports` para el cliente con un límite de 100.
4. **Tu aplicación restringe la función.** Al cargar el panel, verifica el conjunto de características en caché (o llama `listEntitlementGrants`) y renderiza la pestaña de informes solo cuando `advanced_reports` está presente.
5. **El cliente cancela.** Dodo Payments revoca la concesión y dispara `entitlement_grant.revoked`; tu manejador desactiva la función. Si el cliente luego se recupera a través de cobro, `entitlement_grant.delivered` la restaura — no se necesitan cambios de código.

***

## Mejores prácticas

* **Usa ids de función estables y en snake\_case.** Tu código de aplicación verifica estas cadenas; renombrar una es un cambio de ruptura en ambos lados.
* **Una bandera por capacidad.** Prefiere `advanced_reports` + `api_access` como dos derechos sobre un solo `pro_bundle` — la revocación y las mezclas de plan se mantienen limpias.
* **Impulsa el estado desde webhooks, verifica con la API.** Los webhooks mantienen tu base de datos actualizada; el punto de lista es la fuente de verdad para trabajos de reconciliación y pérdidas de caché.
* **Trata `revoked` como inmediato.** Una bandera revocada significa que el cliente ya no está pagando por la función. Verifica en la siguiente solicitud, no en la siguiente sesión.
* **Pon límites en metadatos, no en el código.** Cambiar una cuota luego solo requiere editar el derecho — los nuevos clientes la adoptan automáticamente mientras que las concesiones existentes mantienen su instantánea comprada.
