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

# Adaptador Fastify

> Aprenda como integrar os Pagamentos Dodo com seu projeto Fastify App Router usando nosso Adaptador NextJS. Cobre checkout, portal do cliente, webhooks e configuração de ambiente seguro.

<CardGroup cols={2}>
  <Card title="Checkout Handler" icon="cart-shopping" href="#checkout-route-handler">
    Integre o checkout do Dodo Payments ao seu app Fastify.
  </Card>

  <Card title="Customer Portal" icon="user" href="#customer-portal-route-handler">
    Permita que os clientes gerenciem assinaturas e detalhes.
  </Card>

  <Card title="Webhooks" icon="bell" href="#webhook-route-handler">
    Receba e processe eventos webhook do Dodo Payments.
  </Card>
</CardGroup>

## Instalação

<Steps>
  <Step title="Install the package">
    Execute o seguinte comando na raiz do projeto:

    ```bash theme={null}
    npm install @dodopayments/fastify
    ```
  </Step>

  <Step title="Set up environment variables">
    Crie um <code>.env</code> na raiz do projeto:

    ```env expandable theme={null}
    DODO_PAYMENTS_API_KEY=your-api-key
    DODO_PAYMENTS_RETURN_URL=https://yourapp.com/success
    DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
    DODO_PAYMENTS_ENVIRONMENT="test_mode" or "live_mode""
    ```

    <Warning>
      Nunca comite seu <code>.env</code> ou seus segredos no controle de versão.
    </Warning>
  </Step>
</Steps>

## Exemplos de Manipuladores de Rota

<Info>
  Todos os exemplos presumem que você está usando o Fastify App Router.
</Info>

<Tabs>
  <Tab title="Checkout Handler">
    <Info>
      Use este manipulador para integrar o checkout do Dodo Payments ao seu app Fastify. Suporta fluxos de pagamento estáticos (GET), dinâmicos (POST) e de sessão (POST).
    </Info>

    <CodeGroup>
      ```typescript Fastify Route Handler expandable theme={null}
        // route.ts
        import { Checkout } from '@dodopayments/fastify';
        import Fastify from 'fastify'

        const fastify = Fastify({})
        const checkoutGet = Checkout({
            bearerToken: process.env.DODO_PAYMENTS_API_KEY,
            environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
            returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
            type: 'static'
        });

        const checkoutPost = Checkout({
            bearerToken: process.env.DODO_PAYMENTS_API_KEY,
            environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
            returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
            type: 'dynamic'
        });

        const checkoutSession = Checkout({
            bearerToken: process.env.DODO_PAYMENTS_API_KEY,
            environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
            returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
            type: 'session'
        });

        fastify.get('/api/checkout', checkoutGet.getHandler);
        fastify.post('/api/checkout', checkoutPost.postHandler);
        fastify.post('/api/checkout-session', checkoutSession.postHandler);
      ```
    </CodeGroup>

    <CodeGroup>
      ```curl Static Checkout Curl example expandable theme={null}
      curl --request GET \
      --url 'https://example.com/api/checkout?productId=pdt_fqJhl7pxKWiLhwQR042rh' \
      --header 'User-Agent: insomnia/11.2.0' \
      --cookie mode=test
      ```
    </CodeGroup>

    <CodeGroup>
      ```curl Dynamic Checkout Curl example expandable theme={null}
      curl --request POST \
      --url https://example.com/api/checkout \
      --header 'Content-Type: application/json' \
      --header 'User-Agent: insomnia/11.2.0' \
      --cookie mode=test \
      --data '{
      "billing": {
        "city": "Texas",
        "country": "US",
        "state": "Texas",
        "street": "56, hhh",
        "zipcode": "560000"
      },
      "customer": {
        "email": "test@example.com",
        	"name": "test"
      },
      "metadata": {},
      "payment_link": true,
        "product_id": "pdt_QMDuvLkbVzCRWRQjLNcs",
        "quantity": 1,
        "billing_currency": "USD",
        "discount_codes": ["IKHZ23M9GQ"],
        "return_url": "https://example.com",
        "trial_period_days": 10
      }'
      ```
    </CodeGroup>

    <CodeGroup>
      ```curl Checkout Session Curl example expandable theme={null}
      curl --request POST \
      --url https://example.com/api/checkout-session \
      --header 'Content-Type: application/json' \
      --header 'User-Agent: insomnia/11.2.0' \
      --cookie mode=test \
      --data '{
      "product_cart": [
        {
          "product_id": "pdt_QMDuvLkbVzCRWRQjLNcs",
          "quantity": 1
        }
      ],
      "customer": {
        "email": "test@example.com",
        "name": "test"
      },
      "return_url": "https://example.com/success"
      }'
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Customer Portal Handler">
    <Info>
      Use este manipulador para permitir que os clientes gerenciem suas assinaturas e detalhes por meio do portal do cliente do Dodo Payments.
    </Info>

    <CodeGroup>
      ```typescript Fastify Route Handler expandable theme={null}
      // route.ts
      import { CustomerPortal } from "@dodopayments/fastify";
      import Fastify from 'fastify'

      const fastify = Fastify({})
      const customerPortalHandler = CustomerPortal({
          bearerToken: process.env.DODO_PAYMENTS_API_KEY,
          environment: process.env.DODO_PAYMENTS_ENVIRONMENT
      });
      fastify.get('/api/customer-portal', customerPortalHandler);
      ```
    </CodeGroup>

    <CodeGroup>
      ```curl Customer Portal Curl example expandable theme={null}
      curl --request GET \
      --url 'https://example.com/api/customer-portal?customer_id=cus_9VuW4K7O3GHwasENg31m&send_email=true' \
      --header 'User-Agent: insomnia/11.2.0' \
      --cookie mode=test
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Webhook Handler">
    <Info>
      Use este manipulador para receber e processar eventos webhook do Dodo Payments de forma segura no seu app Fastify.
    </Info>

    <CodeGroup>
      ```typescript Fastify Route Handler expandable theme={null}
      // route.ts
      import Fastify from 'fastify'
      import { Webhooks } from '@dodopayments/fastify'

      const fastify = Fastify({})
      fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
          done(null, body)
      })

      fastify.post('/api/webhooks', Webhooks({
      webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
      onPayload: async (payload) => {
          // Handle Payload Here
          console.log(payload)
      }
      }));

      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Manipulador de Rota de Checkout

<Info>
  O Dodo Payments suporta três tipos de fluxos de pagamento para integrar pagamentos ao seu site, e este adaptador suporta todos os tipos de fluxos de pagamento.
</Info>

* **Links de Pagamento Estáticos:** URLs compartilháveis instantaneamente para coleta de pagamento rápida e sem código.
* **Links de Pagamento Dinâmicos:** Gere programaticamente links de pagamento com detalhes personalizados usando a API ou SDKs.
* **Sessões de Checkout:** Crie experiências de checkout seguras e personalizáveis com carrinhos de produtos pré-configurados e detalhes do cliente.

<AccordionGroup>
  <Accordion title="Static Checkout (GET)">
    ### Supported Query Parameters

    <ParamField query="productId" type="string" required>
      Identificador do produto (por exemplo, <code>?productId=pdt\_nZuwz45WAs64n3l07zpQR</code>).
    </ParamField>

    <ParamField query="quantity" type="integer">
      Quantidade do produto.
    </ParamField>

    <ParamField query="fullName" type="string">
      Nome completo do cliente.
    </ParamField>

    <ParamField query="firstName" type="string">
      Nome do cliente.
    </ParamField>

    <ParamField query="lastName" type="string">
      Sobrenome do cliente.
    </ParamField>

    <ParamField query="email" type="string">
      Endereço de email do cliente.
    </ParamField>

    <ParamField query="country" type="string">
      País do cliente.
    </ParamField>

    <ParamField query="addressLine" type="string">
      Linha de endereço do cliente.
    </ParamField>

    <ParamField query="city" type="string">
      Cidade do cliente.
    </ParamField>

    <ParamField query="state" type="string">
      Estado/província do cliente.
    </ParamField>

    <ParamField query="zipCode" type="string">
      CEP/código postal do cliente.
    </ParamField>

    <ParamField query="disableFullName" type="boolean">
      Desativar campo de nome completo.
    </ParamField>

    <ParamField query="disableFirstName" type="boolean">
      Desativar campo de nome.
    </ParamField>

    <ParamField query="disableLastName" type="boolean">
      Desativar campo de sobrenome.
    </ParamField>

    <ParamField query="disableEmail" type="boolean">
      Desativar campo de email.
    </ParamField>

    <ParamField query="disableCountry" type="boolean">
      Desativar campo de país.
    </ParamField>

    <ParamField query="disableAddressLine" type="boolean">
      Desativar campo de endereço.
    </ParamField>

    <ParamField query="disableCity" type="boolean">
      Desativar campo de cidade.
    </ParamField>

    <ParamField query="disableState" type="boolean">
      Desativar campo de estado.
    </ParamField>

    <ParamField query="disableZipCode" type="boolean">
      Desativar campo de CEP.
    </ParamField>

    <ParamField query="paymentCurrency" type="string">
      Especifique a moeda do pagamento (por exemplo, <code>USD</code>).
    </ParamField>

    <ParamField query="showCurrencySelector" type="boolean">
      Exibir seletor de moeda.
    </ParamField>

    <ParamField query="paymentAmount" type="integer">
      Especifique o valor do pagamento (por exemplo, <code>1000</code> para \$10,00).
    </ParamField>

    <ParamField query="showDiscounts" type="boolean">
      Exibir campos de desconto.
    </ParamField>

    <ParamField query="metadata_*" type="string">
      Qualquer parâmetro de consulta que comece com <code>metadata\_</code> será passado como metadados.
    </ParamField>

    <Warning>
      Se <code>productId</code> estiver ausente, o handler retorna uma resposta 400. Parâmetros de consulta inválidos também resultam em uma resposta 400.
    </Warning>

    ### Formato de Resposta

    O checkout estático retorna uma resposta JSON com a URL de checkout:

    ```json theme={null}
    {
      "checkout_url": "https://checkout.dodopayments.com/..."
    }
    ```
  </Accordion>

  <Accordion title="Dynamic Checkout (POST)">
    * Envie os parâmetros como um corpo JSON em uma requisição POST.
    * Suporta pagamentos únicos e recorrentes.
    * Para a lista completa de campos de body suportados em POST, consulte:
      * [Request body for a One Time Payment Product](https://docs.dodopayments.com/api-reference/payments/post-payments)
      * [Request body for a Subscription Product](https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions)

    ### Formato de Resposta

    O checkout dinâmico retorna uma resposta JSON com a URL de checkout:

    ```json theme={null}
    {
      "checkout_url": "https://checkout.dodopayments.com/..."
    }
    ```
  </Accordion>

  <Accordion title="Checkout Sessions (POST)">
    As sessões de checkout oferecem uma experiência de checkout hospedada e mais segura que gerencia todo o fluxo de pagamento tanto para compras únicas quanto para assinaturas, com controle total de personalização.

    Consulte o [Guia de Integração de Sessões de Checkout](https://docs.dodopayments.com/developer-resources/checkout-session) para mais detalhes e uma lista completa de campos suportados.

    ### Formato de Resposta

    As sessões de checkout retornam uma resposta JSON com a URL de checkout:

    ```json theme={null}
    {
      "checkout_url": "https://checkout.dodopayments.com/session/..."
    }
    ```
  </Accordion>
</AccordionGroup>

## Manipulador de Rota do Portal do Cliente

O Manipulador de Rota do Portal do Cliente permite que você integre perfeitamente o portal do cliente dos Pagamentos Dodo em sua aplicação Fastify.

### Parâmetros de Consulta

<ParamField query="customer_id" type="string" required>
  O ID do cliente para a sessão do portal (por exemplo, <code>?customer\_id=cus\_123</code>).
</ParamField>

<ParamField query="send_email" type="boolean">
  Se estiver definido como <code>true</code>, envia um email ao cliente com o link do portal.
</ParamField>

<Warning>
  Retorna 400 se <code>customer\_id</code> estiver ausente.
</Warning>

## Manipulador de Rota de Webhook

* **Método:** Apenas solicitações POST são suportadas. Outros métodos retornam 405.
* **Verificação de Assinatura:** Verifica a assinatura do webhook usando <code>webhookKey</code>. Retorna 401 se a verificação falhar.
* **Validação de Payload:** Validado com Zod. Retorna 400 para payloads inválidos.
* **Tratamento de Erros:**
  * 401: Assinatura inválida
  * 400: Payload inválido
  * 500: Erro interno durante a verificação
* **Roteamento de Eventos:** Chama o manipulador de eventos apropriado com base no tipo de payload.

### Handlers de Evento Webhook Suportados

<CodeGroup>
  ```typescript Typescript expandable theme={null}
  onPayload?: (payload: WebhookPayload) => Promise<void>;
  onPaymentSucceeded?: (payload: WebhookPayload) => Promise<void>;
  onPaymentFailed?: (payload: WebhookPayload) => Promise<void>;
  onPaymentProcessing?: (payload: WebhookPayload) => Promise<void>;
  onPaymentCancelled?: (payload: WebhookPayload) => Promise<void>;
  onRefundSucceeded?: (payload: WebhookPayload) => Promise<void>;
  onRefundFailed?: (payload: WebhookPayload) => Promise<void>;
  onDisputeOpened?: (payload: WebhookPayload) => Promise<void>;
  onDisputeExpired?: (payload: WebhookPayload) => Promise<void>;
  onDisputeAccepted?: (payload: WebhookPayload) => Promise<void>;
  onDisputeCancelled?: (payload: WebhookPayload) => Promise<void>;
  onDisputeChallenged?: (payload: WebhookPayload) => Promise<void>;
  onDisputeWon?: (payload: WebhookPayload) => Promise<void>;
  onDisputeLost?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionActive?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionOnHold?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionRenewed?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionPlanChanged?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionCancelled?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionFailed?: (payload: WebhookPayload) => Promise<void>;
  onSubscriptionExpired?: (payload: WebhookPayload) => Promise<void>;
  onLicenseKeyCreated?: (payload: WebhookPayload) => Promise<void>;
  ```
</CodeGroup>

***

## Prompt para LLM

```
Você é um assistente especialista em desenvolvimento Fastify. Sua tarefa é guiar um usuário na integração do adaptador @dodopayments/fastify em seu projeto Fastify existente.

O adaptador @dodopayments/fastify fornece manipuladores de rota para Checkout, Portal do Cliente e funcionalidades de Webhook dos Pagamentos Dodo, projetados para se conectar diretamente a um aplicativo Fastify.

Primeiro, instale o pacote necessário. Use o gerenciador de pacotes apropriado para o projeto do usuário (npm, yarn ou bun):

npm install @dodopayments/fastify

---

Aqui está como você deve estruturar sua resposta:

1. Pergunte ao usuário quais funcionalidades ele deseja integrar.

"Quais partes do adaptador @dodopayments/fastify você gostaria de integrar em seu projeto? Você pode escolher uma ou mais das seguintes:

- Manipulador de Rota de Checkout (para lidar com checkouts de produtos)
- Manipulador de Rota do Portal do Cliente (para gerenciar assinaturas/detalhes do cliente)
- Manipulador de Rota de Webhook (para receber eventos de webhook dos Pagamentos Dodo)
- Todos (integrar os três)"

---

2. Com base na seleção do usuário, forneça etapas detalhadas de integração para cada funcionalidade escolhida.

---

**Se o Manipulador de Rota de Checkout for selecionado:**

**Propósito**: Este manipulador redireciona os usuários para a página de checkout dos Pagamentos Dodo.

**Integração**:
Crie duas rotas em seu aplicativo Fastify — uma para checkout estático (GET) e uma para checkout dinâmico (POST).

import { Checkout } from '@dodopayments/fastify';
import Fastify from 'fastify'

const fastify = Fastify({})
const checkoutGet = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    type: 'static'
});

const checkoutPost = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    type: 'dynamic'
});

const checkoutSession = Checkout({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT,
    returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
    type: 'session'
});

fastify.get('/api/checkout', checkoutGet.getHandler);
fastify.post('/api/checkout', checkoutPost.postHandler);
fastify.post('/api/checkout-session', checkoutSession.postHandler);

Opções de Configuração:

    bearerToken: Sua chave de API dos Pagamentos Dodo (recomendado que seja armazenada na variável de ambiente DODO_PAYMENTS_API_KEY).

    returnUrl (opcional): URL para redirecionar o usuário após o checkout bem-sucedido.

    environment: "test_mode" ou "live_mode"

    type: "static" (GET), "dynamic" (POST) ou "session" (POST)

GET (checkout estático) espera parâmetros de consulta:

    productId (obrigatório)

    quantity, campos do cliente (fullName, email, etc.) e metadados (metadata_*) são opcionais.

    Retorna: {"checkout_url": "https://checkout.dodopayments.com/..."}

POST (checkout dinâmico) espera um corpo JSON com detalhes de pagamento (único ou assinatura). Retorna: {"checkout_url": "https://checkout.dodopayments.com/..."}. Consulte a documentação para o esquema completo do POST:

    Pagamentos únicos: https://docs.dodopayments.com/api-reference/payments/post-payments

    Assinaturas: https://docs.dodopayments.com/api-reference/subscriptions/post-subscriptions

POST (sessões de checkout) - (Recomendado) Uma experiência de checkout mais personalizável. Retorna JSON com checkout_url: Os parâmetros são enviados como um corpo JSON. Suporta pagamentos únicos e recorrentes. Retorna: {"checkout_url": "https://checkout.dodopayments.com/session/..."}. Para uma lista completa de campos suportados, consulte:

    Guia de Integração de Sessões de Checkout: https://docs.dodopayments.com/developer-resources/checkout-session

Se o Manipulador de Rota do Portal do Cliente for selecionado:

Propósito: Esta rota permite que os clientes gerenciem suas assinaturas através do portal dos Pagamentos Dodo.

Integração:

import { CustomerPortal } from "@dodopayments/fastify";
import Fastify from 'fastify'

const fastify = Fastify({})
const customerPortalHandler = CustomerPortal({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: process.env.DODO_PAYMENTS_ENVIRONMENT
});
fastify.get('/api/customer-portal', customerPortalHandler);

Parâmetros de Consulta:

    customer_id (obrigatório): por exemplo, ?customer_id=cus_123

    send_email (opcional): se verdadeiro, o cliente recebe por e-mail o link do portal

Retorna 400 se customer_id estiver ausente.

Se o Manipulador de Rota de Webhook for selecionado:

Propósito: Processa eventos de webhook recebidos dos Pagamentos Dodo para acionar eventos em seu aplicativo.

Integração:

import Fastify from 'fastify'
import { Webhooks } from '@dodopayments/fastify'

const fastify = Fastify({})
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
    done(null, body)
})

fastify.post('/api/webhooks', Webhooks({
  webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
  onPayload: async (payload) => {
    // Manipule o Payload Aqui
    console.log(payload)
  }
}));

Recursos:

    Apenas o método POST é permitido — outros retornam 405

    A verificação de assinatura é realizada usando webhookKey. Retorna 401 se inválido.

    Validação de payload baseada em Zod. Retorna 400 se o esquema for inválido.

    Todos os manipuladores são funções assíncronas.

Manipuladores de Eventos de Webhook Suportados:

Você pode passar qualquer um dos seguintes manipuladores:

    onPayload

    onPaymentSucceeded

    onPaymentFailed

    onPaymentProcessing

    onPaymentCancelled

    onRefundSucceeded

    onRefundFailed

    onDisputeOpened, onDisputeExpired, onDisputeAccepted, onDisputeCancelled, onDisputeChallenged, onDisputeWon, onDisputeLost

    onSubscriptionActive, onSubscriptionOnHold, onSubscriptionRenewed, onSubscriptionPaused, onSubscriptionPlanChanged, onSubscriptionCancelled, onSubscriptionFailed, onSubscriptionExpired

    onLicenseKeyCreated

Configuração de Variáveis de Ambiente:

Certifique-se de definir estas variáveis de ambiente em seu projeto:

DODO_PAYMENTS_API_KEY=your-api-key
DODO_PAYMENTS_RETURN_URL=https://yourapp.com/success
DODO_PAYMENTS_WEBHOOK_KEY=your-webhook-secret
DODO_PAYMENTS_ENVIRONMENT="test_mode" ou "live_mode""

Use estas dentro do seu código como:

process.env.DODO_PAYMENTS_API_KEY
process.env.DODO_PAYMENTS_WEBHOOK_KEY

Nota de Segurança: NÃO comite segredos no controle de versão. Use arquivos .env localmente e gerenciadores de segredos em ambientes de implantação (por exemplo, AWS, Vercel, Heroku, etc.).

Use isto dentro do seu código como:

process.env.DODO_PAYMENTS_API_KEY
process.env.DODO_PAYMENTS_WEBHOOK_KEY

Nota de Segurança: Não envie segredos para o controle de versão. Use arquivos .env localmente e gerenciadores de segredos em ambientes de implantação (ex.: AWS, Vercel, Heroku, etc.).
```
