> ## 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.

# Feature Flag Entitlement

> Attiva funzionalità nella tua applicazione in base a un acquisto. I diritti di feature flag forniscono una capacità booleana istantaneamente al pagamento e la revocano automaticamente alla cancellazione.

<Info>
  Un diritto di feature flag trasforma Dodo Payments in un negozio di feature flag consapevole del billing. Associa un flag come `advanced_reports` a un prodotto, e ogni cliente pagante ottiene un diritto che la tua applicazione può verificare tramite API o mantenere sincronizzato con webhooks. Nessuna piattaforma esterna, nessun OAuth, nessun passo di consegna — il diritto stesso è la capacità.
</Info>

## Cosa viene consegnato

Nulla lascia Dodo Payments — il diritto **è** il deliverable:

* Al momento dell'acquisto, il diritto viene creato e passa direttamente a `delivered`. Non c'è nessuna fase `pending`, nessuna azione del cliente e nessun modo per il fallimento della consegna.
* Il diritto porta un payload tipizzato `feature`: `{ "feature_type": "boolean", "feature_id": "advanced_reports" }`. La tua applicazione legge `feature_id` per decidere cosa sbloccare.
* Cancellazione, rimborso o revoca manuale sposta il diritto a `revoked`, e la tua applicazione vede il flag scomparire.

Gli usi comuni includono gating di funzionalità basati su piani (Pro sblocca analitica), capacità aggiuntive (aggiornamento "API access"), e programmi di accesso anticipato venduti come acquisti una tantum.

<Note>
  `feature_id` è un identificatore scelto dal merchant, non unico tra le entitlements. Due entitlements possono conferire lo stesso `feature_id` — ad esempio, un piano Pro mensile e annuale che entrambi concedono `advanced_reports`.
</Note>

## Crea un feature flag

<Steps>
  <Step title="Open Entitlements">
    Nel tuo dashboard di Dodo Payments, vai a **Entitlements** e clicca **+** per iniziare un nuovo entitlement, quindi scegli **Feature Flags**.
  </Step>

  <Step title="Name the flag">
    Dai al flag un **Display Name** per il tuo dashboard, un **Feature ID** che la tua applicazione verificherà (il dashboard suggerisce uno dal nome), e una **Description** per far sapere al tuo team cosa controlla.

    <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="Nuovo modulo Feature Flag con nome di visualizzazione, ID funzionalità, descrizione, e voci di metadati chiave-valore" style={{ maxHeight: '500px', width: 'auto' }} width="1196" height="776" data-path="images/entitlements/feature-flags/create.png" />
    </Frame>
  </Step>

  <Step title="Optionally add metadata">
    Attiva **Meta Data** per allegare configurazioni chiave-valore — limiti, nomi di livelli, quote — che vengono consegnati alla tua applicazione insieme al flag. Vedi [Allega limiti con metadati](#attach-limits-with-metadata).
  </Step>

  <Step title="Confirm">
    Clicca **Conferma**. Il flag appare nella tua lista di entitlements, pronto per essere associato ai prodotti.

    <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="Dashboard Entitlements che mostra il feature flag Advanced Reports con il suo riquadro di attività di concessione" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/list.png" />
    </Frame>
  </Step>
</Steps>

## Associa a un prodotto

Apri un prodotto (o creane uno), trova la scheda **Entitlements** e clicca **+** per associare gli entitlements esistenti. Seleziona il tuo feature flag e clicca **Fatto**.

<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="Pannello di associazione Entitlements con il feature flag Advanced Reports selezionato" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-picker.png" />
</Frame>

Il flag associato appare sul modulo del prodotto, e l'anteprima del checkout lo elenca sotto **Includes**.

<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="Modulo del prodotto con il feature flag Advanced Reports associato nella scheda Entitlements" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-to-product.png" />
</Frame>

## Configurazione richiesta

| Campo          | Richiesto | Descrizione                                                                                                |
| -------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| `feature_id`   | Sì        | Identificatore che la tua applicazione verifica, ad es. `advanced_reports`. Non unico tra le entitlements. |
| `feature_type` | Sì        | Tipo di capacità conferita. Solo `boolean` è supportato oggi.                                              |

### Creare via 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>

***

## Allega limiti con metadati

Un flag booleano risponde "questo cliente ha la funzionalità?". I metadati rispondono "con quale configurazione?". I metadati di entitlement accettano valori stringa, intero, numero e booleano, e ogni diritto prende un **istantanea congelata** dei metadati di entitlement al momento della creazione.

Quel comportamento dell'istantanea è ciò che rende sicuro l'uso dei metadati per i limiti di piano:

* Modificare i metadati dell'entitlement in un secondo momento influisce solo sui **futuri** diritti. I clienti mantengono i limiti sotto i quali hanno acquistato.
* L'istantanea viene restituita su ogni diritto come suo campo `metadata`, quindi una chiamata API ti dà sia il flag che la sua configurazione.

Ad esempio, un flag `advanced_reports` con `{ "tier": "pro", "monthly_report_limit": 100 }` consente alla tua applicazione di sbloccare il dashboard *e* applicare il limite di 100 report senza una seconda ricerca. Se successivamente aumenti il limite a 250, i clienti esistenti rimangono a 100 fino a quando non ricevono un nuovo diritto (ad esempio, dopo un cambio di piano).

<Tip>
  Usa i metadati per limiti e configurazioni; usa `feature_id` solo per l'identità. Codificare i limiti nell'id (`advanced_reports_100`) forza un nuovo flag per ogni cambio di limite e interrompe i controlli della tua applicazione.
</Tip>

***

## Verifica le funzionalità di un cliente

Elenca i diritti di feature flag consegnati a un cliente e costruisci l'insieme di caratteristiche abilitate. L'endpoint restituisce una riga per ogni diritto attraverso tutte le entitlements, filtrabile da `integration_type` e `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>
  Il payload `feature` è popolato solo su concessioni `feature_flag`; è `null` per ogni altro tipo di integrazione. Vedi il riferimento API [List Customer Grants](/api-reference/entitlements/list-customer-grants) per la forma completa della risposta.
</Note>

Controllare l'API su ogni richiesta aggiunge latenza al tuo percorso caldo. Memorizza nella cache l'insieme delle funzionalità per cliente con un TTL breve (minuti, non ore) e invalida la cache dal tuo gestore webhook quando un diritto cambia stato — quella combinazione mantiene i controlli veloci e le revoche quasi istantanee.

***

## Ciclo di vita

I diritti di feature flag seguono il ciclo di vita standard [grant lifecycle](/features/entitlements/introduction#how-grants-work) con una semplificazione: non c'è nessun passo di consegna, quindi i diritti non siedono mai in `pending` e non si spostano mai a `failed`.

| Trigger                                                     | Effetto                                                                                                 |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Pagamento una tantum riuscito / abbonamento diventa attivo  | Diritto creato con `status: delivered` e `delivered_at` impostati.                                      |
| Abbonamento in pausa, cancellato o scaduto                  | Diritto revocato con il corrispondente `revocation_reason`.                                             |
| Rimborso su un pagamento una tantum                         | Diritto revocato con `revocation_reason: refund`.                                                       |
| Abbonamento ripristinato (ad esempio, riscossione riuscita) | Il diritto revocato viene ripristinato a `delivered` — stesso diritto `id`, campi di revoca cancellati. |
| Revoca API manuale                                          | Diritto revocato con `revocation_reason: manual`. Non viene ripristinato automaticamente al rinnovo.    |

I diritti sono idempotenti per ogni entitlement e cliente: mentre un cliente ha un diritto non revocato per un flag, acquisti e rinnovi ripetuti non creano duplicati.

***

## Webhooks

Iscriviti agli eventi [`entitlement_grant.*`](/developer-resources/webhooks/intents/entitlement-grant) per rispecchiare i flag nel tuo database invece di effettuare polling:

* `entitlement_grant.created` — arriva già `delivered` con il payload `feature`. Abilita la funzionalità.
* `entitlement_grant.delivered` — si attiva quando un diritto precedentemente revocato viene ripristinato. Riabilita la funzionalità.
* `entitlement_grant.revoked` — accesso ritirato. Disabilita la funzionalità e controlla `revocation_reason` per decidere il tuo messaggio.

```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);
});
```

Non ci sono `entitlement_grant.failed` per i feature flags — la consegna avviene interamente all'interno di Dodo Payments e non può fallire.

***

## Esempio: Il piano Pro sblocca i report avanzati

1. **Crea il flag.** `feature_id: advanced_reports` con metadati `{ "tier": "pro", "monthly_report_limit": 100 }`.
2. **Associalo** al prodotto di abbonamento del tuo Pro Plan.
3. **Un cliente si abbona.** Dodo Payments crea un diritto `delivered` e genera `entitlement_grant.created`; il tuo gestore webhook abilita `advanced_reports` per il cliente con un limite di 100.
4. **La tua app attiva la funzione.** Al caricamento del dashboard, controlla l'insieme delle funzionalità memorizzato nella cache (o chiama `listEntitlementGrants`) e visualizza la scheda dei report solo quando `advanced_reports` è presente.
5. **Il cliente cancella.** Dodo Payments revoca il diritto e genera `entitlement_grant.revoked`; il tuo gestore disabilita la funzione. Se il cliente in seguito si riprende tramite riscossione, `entitlement_grant.delivered` la ripristina — nessuna modifica al codice necessaria.

***

## Migliori pratiche

* **Usa ID funzionalità stabili in snake\_case.** Il codice della tua applicazione controlla queste stringhe; rinominare uno è un cambiamento radicale su entrambi i lati.
* **Un flag per capacità.** Preferisci `advanced_reports` + `api_access` come due entitlements su un singolo `pro_bundle` — revoca e combinazioni di piani rimangono pulite.
* **Guida lo stato dai webhooks, verifica con l'API.** I webhooks mantengono il tuo database aggiornato; l'endpoint della lista è la fonte della verità per i lavori di riconciliazione e gli eventi cache miss.
* **Tratta `revoked` come immediato.** Un flag revocato significa che il cliente non sta più pagando per la funzionalità. Attivalo alla prossima richiesta, non alla prossima sessione.
* **Metti i limiti nei metadati, non nel codice.** Cambiare una quota richiede solo di modificare la entitlement — i nuovi clienti la acquisiscono automaticamente mentre i diritti esistenti mantengono la loro istantanea acquistata.

## Best practices

* **Use stable, snake\_case feature ids.** Your application code checks these strings; renaming one is a breaking change on both sides.
* **One flag per capability.** Prefer `advanced_reports` + `api_access` as two entitlements over a single `pro_bundle` — revocation and plan mixes stay clean.
* **Drive state from webhooks, verify with the API.** Webhooks keep your database current; the list endpoint is the source of truth for reconciliation jobs and cache misses.
* **Treat `revoked` as immediate.** A revoked flag means the customer is no longer paying for the feature. Gate on the next request, not the next session.
* **Put limits in metadata, not in code.** Changing a quota then only requires editing the entitlement — new customers pick it up automatically while existing grants keep their purchased snapshot.
