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

# Entitlement de Feature Flag

> Bloqueie funcionalidades em sua própria aplicação através de uma compra. Entitlements de feature flags entregam uma capacidade booleana instantaneamente no pagamento e a revogam automaticamente no cancelamento.

<Info>
  Um entitlement de feature flag transforma o Dodo Payments em um armazenamento de flags de recurso ciente de faturamento. Anexe uma flag como `advanced_reports` a um produto, e todo cliente pagante recebe uma concessão que sua aplicação pode verificar via API ou manter sincronizado com webhooks. Nenhuma plataforma externa, sem OAuth, sem etapa de entrega — a própria concessão é a capacidade.
</Info>

## O que é entregue

Nada sai do Dodo Payments — a concessão **é** a entrega:

* Na compra, a concessão é criada e move-se diretamente para `delivered`. Não há fase `pending`, nenhuma ação do cliente, e nenhuma possibilidade de falha na entrega.
* A concessão carrega um payload digitado `feature`: `{ "feature_type": "boolean", "feature_id": "advanced_reports" }`. Sua aplicação lê `feature_id` para decidir o que desbloquear.
* Cancelamento, reembolso, ou revogação manual movem a concessão para `revoked`, e sua aplicação vê a flag desaparecer.

Usos comuns incluem feature gating baseado em plano (Pro desbloqueia analytics), capacidades adicionais (um upgrade de "acesso à API"), e programas de acesso antecipado vendidos como compras únicas.

<Note>
  `feature_id` é um identificador escolhido pelo comerciante, não único entre os entitlements. Dois entitlements podem conferir o mesmo `feature_id` — por exemplo, um plano Pro mensal e anual ambos concedendo `advanced_reports`.
</Note>

## Criar uma feature flag

<Steps>
  <Step title="Open Entitlements">
    No seu painel do Dodo Payments, vá para **Entitlements** e clique em **+** para iniciar um novo entitlement, depois escolha **Feature Flags**.
  </Step>

  <Step title="Name the flag">
    Dê à flag um **Nome de Exibição** para seu painel, um **ID de Recurso** que sua aplicação irá verificar (o painel sugere um a partir do nome), e uma **Descrição** para que sua equipe saiba o que 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="Novo formulário de Feature Flag com nome de exibição, ID de recurso, descrição e entradas de metadados chave-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">
    Alternar **Meta Data** para anexar configuração chave-valor — limites, nomes de níveis, cotas — que é entregue à sua aplicação junto com a flag. Veja [Anexar limites com metadados](#attach-limits-with-metadata).
  </Step>

  <Step title="Confirm">
    Clique em **Confirmar**. A flag aparece na sua lista de entitlements, pronta para ser anexada aos produtos.

    <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="Painel de Entitlements mostrando a feature flag de Advanced Reports com seu painel de atividades de concessão" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/list.png" />
    </Frame>
  </Step>
</Steps>

## Anexar a um produto

Abra um produto (ou crie um), encontre o cartão **Entitlements**, e clique em **+** para anexar entitlements existentes. Selecione sua feature flag e clique em **Concluir**.

<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="Painel de anexação de Entitlements com a feature flag de Advanced Reports selecionada" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-picker.png" />
</Frame>

A flag anexada aparece no formulário do produto, e a visualização da finalização da compra a lista em **Inclui**.

<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="Formulário de produto com a feature flag de Advanced Reports anexada no cartão de Entitlements" style={{ maxHeight: '500px', width: 'auto' }} width="1316" height="898" data-path="images/entitlements/feature-flags/attach-to-product.png" />
</Frame>

## Configuração obrigatória

| Campo          | Obrigatório | Descrição                                                                                                   |
| -------------- | ----------- | ----------------------------------------------------------------------------------------------------------- |
| `feature_id`   | Sim         | Identificador que sua aplicação verifica, por exemplo, `advanced_reports`. Não único entre os entitlements. |
| `feature_type` | Sim         | Tipo de capacidade conferida. Apenas `boolean` é suportado hoje.                                            |

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

***

## Anexar limites com metadados

Uma flag booleana responde "este cliente possui o recurso?". Os metadados respondem "com qual configuração?". Os metadados de entitlement aceitam valores de string, inteiro, número e booleano, e cada concessão toma um **instantâneo congelado** dos metadados do entitlement no momento em que é criada.

Esse comportamento de instantâneo é o que torna os metadados seguros para usar em limites de plano:

* Editar os metadados do entitlement posteriormente afeta apenas as concessões **futuras**. Os clientes mantêm os limites sob os quais foram comprados.
* O instantâneo é retornado em cada concessão como seu campo `metadata`, então uma chamada API fornece tanto a flag quanto sua configuração.

Por exemplo, uma flag `advanced_reports` com `{ "tier": "pro", "monthly_report_limit": 100 }` permite que sua aplicação desbloqueie o dashboard *e* imponha a cota de 100 relatórios sem uma segunda consulta. Se mais tarde você aumentar o limite para 250, os clientes existentes permanecem em 100 até receberem uma nova concessão (por exemplo, após uma mudança de plano).

<Tip>
  Use metadados para limites e configuração; use `feature_id` apenas para identidade. Codificar limites no id (`advanced_reports_100`) força uma nova flag para cada mudança de limite e quebra as verificações da sua aplicação.
</Tip>

***

## Verificar recursos de um cliente

Liste concessões de feature-flag entregues a um cliente e construa o conjunto de recursos habilitados. O endpoint retorna uma linha por concessão em todos os entitlements, filtrável por `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>
  O payload `feature` é populado apenas nas concessões `feature_flag`; ele é `null` para todos os outros tipos de integração. Veja a referência de API [List Customer Grants](/api-reference/entitlements/list-customer-grants) para a forma completa da resposta.
</Note>

Verificar a API em cada solicitação adiciona latência ao seu caminho quente. Armazene em cache o conjunto de funcionalidades por cliente com um TTL curto (minutos, não horas), e invalide o cache do seu manipulador de webhook quando uma concessão mudar de estado — essa combinação mantém as verificações rápidas e as revogações quase instantâneas.

***

## Ciclo de vida

As concessões de feature flag seguem o [ciclo de vida padrão da concessão](/features/entitlements/introduction#how-grants-work) com uma simplificação: não há etapa de entrega, então as concessões nunca se encontram em `pending` e nunca se movem para `failed`.

| Acionador                                                | Efeito                                                                                                 |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Pagamento único bem-sucedido / assinatura torna-se ativa | Concessão criada com `status: delivered` e `delivered_at` definidos.                                   |
| Assinatura em espera, cancelada ou expirada              | Concessão revogada com `revocation_reason` correspondente.                                             |
| Reembolso em um pagamento único                          | Concessão revogada com `revocation_reason: refund`.                                                    |
| Assinatura recupera (por exemplo, cobrança bem-sucedida) | A concessão revogada é restaurada para `delivered` — mesma concessão `id`, campos de revogação limpos. |
| Revogação manual via API                                 | Concessão revogada com `revocation_reason: manual`. Não é restaurada automaticamente na renovação.     |

As concessões são idempotentes por entitlement e cliente: enquanto um cliente tiver uma concessão não revogada para uma flag, compras repetidas e renovações não criam duplicatas.

***

## Webhooks

Assine os [eventos `entitlement_grant.*`](/developer-resources/webhooks/intents/entitlement-grant) para espelhar flags no seu próprio banco de dados em vez de fazer polling:

* `entitlement_grant.created` — chega já `delivered` com o payload `feature`. Habilite o recurso.
* `entitlement_grant.delivered` — dispara quando uma concessão anteriormente revogada é restaurada. Re-habilite o recurso.
* `entitlement_grant.revoked` — acesso retirado. Desabilite o recurso e verifique `revocation_reason` para decidir sua mensagem.

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

Não há `entitlement_grant.failed` para feature flags — a entrega acontece inteiramente dentro do Dodo Payments e não pode falhar.

***

## Exemplo: Plano Pro desbloqueia relatórios avançados

1. **Crie a flag.** `feature_id: advanced_reports` com metadados `{ "tier": "pro", "monthly_report_limit": 100 }`.
2. **Anexe-a** ao seu produto de assinatura Pro Plan.
3. **Um cliente se inscreve.** O Dodo Payments cria uma concessão `delivered` e dispara `entitlement_grant.created`; seu manipulador de webhook habilita `advanced_reports` para o cliente com um limite de 100.
4. **Sua aplicação bloqueia o recurso.** Ao carregar o dashboard, verifique o conjunto de funcionalidades em cache (ou chame `listEntitlementGrants`) e exiba a aba de relatórios apenas quando `advanced_reports` estiver presente.
5. **O cliente cancela.** O Dodo Payments revoga a concessão e dispara `entitlement_grant.revoked`; seu manipulador desabilita o recurso. Se o cliente se recuperar posteriormente por meio de dunning, `entitlement_grant.delivered` o restaura — nenhuma alteração de código necessária.

***

## Melhores práticas

* **Use ids de recursos estáveis e em snake\_case.** O código da sua aplicação verifica essas strings; renomear uma é uma mudança quebradora em ambos os lados.
* **Uma flag por capacidade.** Prefira `advanced_reports` + `api_access` como dois entitlements ao invés de um único `pro_bundle` — a revogação e as misturas de planos permanecem limpas.
* **Dirija o estado a partir de webhooks, verifique com a API.** Webhooks mantêm seu banco de dados atualizado; o endpoint de lista é a fonte de verdade para trabalhos de reconciliação e falhas de cache.
* **Trate `revoked` como imediato.** Uma flag revogada significa que o cliente não está mais pagando pelo recurso. Bloqueie na próxima solicitação, não na próxima sessão.
* **Coloque limites em metadados, não em código.** Alterar uma cota só requer editar o entitlement — novos clientes a capturam automaticamente enquanto concessões existentes mantêm seu instantâneo comprado.
