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

# Fastify Adaptor

> Lär dig hur du integrerar Dodo Payments med ditt Fastify App Router-projekt med hjälp av vår NextJS Adaptor. Täcker kassa, kundportal, webhooks och säker miljöinställning.

<CardGroup cols={2}>
  <Card title="Checkout Handler" icon="cart-shopping" href="#checkout-route-handler">
    Integrera Dodo Payments kassa i din Fastify-app.
  </Card>

  <Card title="Customer Portal" icon="user" href="#customer-portal-route-handler">
    Låt kunder hantera abonnemang och uppgifter.
  </Card>

  <Card title="Webhooks" icon="bell" href="#webhook-route-handler">
    Ta emot och bearbeta webhookhändelser från Dodo Payments.
  </Card>
</CardGroup>

## Installation

<Steps>
  <Step title="Install the package">
    Kör följande kommando i projektroten:

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

  <Step title="Set up environment variables">
    Skapa en <code>.env</code>-fil i projektroten:

    ```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>
      Checka aldrig in din <code>.env</code>-fil eller hemligheter i versionshanteringen.
    </Warning>
  </Step>
</Steps>

## Exempel på Routhanterare

<Info>
  Alla exempel förutsätter att du använder Fastify App Router.
</Info>

<Tabs>
  <Tab title="Checkout Handler">
    <Info>
      Använd denna hanterare för att integrera Dodo Payments kassa i din Fastify-app. Stöder statiska (GET), dynamiska (POST) och sessionsbaserade (POST) betalflöden.
    </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>
      Använd denna hanterare för att låta kunder hantera sina abonnemang och uppgifter via Dodo Payments kundportal.
    </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>
      Använd denna hanterare för att säkert ta emot och bearbeta webhookhändelser från Dodo Payments i din Fastify-app.
    </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>

## Kassa Routhanterare

<Info>
  Dodo Payments stöder tre typer av betalflöden för att integrera betalningar på din webbplats, och denna adaptrar stöder alla typer.
</Info>

* **Statiska Betalningslänkar:** Omedelbart delbara URL:er för snabb, kodfri insamling av betalningar.
* **Dynamiska Betalningslänkar:** Programmatisk generering av betalningslänkar med anpassade detaljer med hjälp av API eller SDK:er.
* **Kassa Sessioner:** Skapa säkra, anpassningsbara kassaupplevelser med förkonfigurerade produktvagnar och kunddetaljer.

<AccordionGroup>
  <Accordion title="Static Checkout (GET)">
    ### Frågeparametrar

    <ParamField query="productId" type="string" required>
      Produktidentifierare (t.ex. <code>?productId=pdt\_nZuwz45WAs64n3l07zpQR</code>).
    </ParamField>

    <ParamField query="quantity" type="integer">
      Antal av produkten.
    </ParamField>

    <ParamField query="fullName" type="string">
      Kundens fullständiga namn.
    </ParamField>

    <ParamField query="firstName" type="string">
      Kundens förnamn.
    </ParamField>

    <ParamField query="lastName" type="string">
      Kundens efternamn.
    </ParamField>

    <ParamField query="email" type="string">
      Kundens e-postadress.
    </ParamField>

    <ParamField query="country" type="string">
      Kundens land.
    </ParamField>

    <ParamField query="addressLine" type="string">
      Kundens adressrad.
    </ParamField>

    <ParamField query="city" type="string">
      Kundens stad.
    </ParamField>

    <ParamField query="state" type="string">
      Kundens delstat/provins.
    </ParamField>

    <ParamField query="zipCode" type="string">
      Kundens postnummer.
    </ParamField>

    <ParamField query="disableFullName" type="boolean">
      Inaktivera fältet för fullständigt namn.
    </ParamField>

    <ParamField query="disableFirstName" type="boolean">
      Inaktivera fältet för förnamn.
    </ParamField>

    <ParamField query="disableLastName" type="boolean">
      Inaktivera fältet för efternamn.
    </ParamField>

    <ParamField query="disableEmail" type="boolean">
      Inaktivera e-postfältet.
    </ParamField>

    <ParamField query="disableCountry" type="boolean">
      Inaktivera landfältet.
    </ParamField>

    <ParamField query="disableAddressLine" type="boolean">
      Inaktivera adressradsfältet.
    </ParamField>

    <ParamField query="disableCity" type="boolean">
      Inaktivera stadfältet.
    </ParamField>

    <ParamField query="disableState" type="boolean">
      Inaktivera fältet för delstat.
    </ParamField>

    <ParamField query="disableZipCode" type="boolean">
      Inaktivera fältet för postnummer.
    </ParamField>

    <ParamField query="paymentCurrency" type="string">
      Ange betalningsvalutan (t.ex. <code>USD</code>).
    </ParamField>

    <ParamField query="showCurrencySelector" type="boolean">
      Visa valutaväljaren.
    </ParamField>

    <ParamField query="paymentAmount" type="integer">
      Ange betalningsbeloppet (t.ex. <code>1000</code> för \$10.00).
    </ParamField>

    <ParamField query="showDiscounts" type="boolean">
      Visa rabattfält.
    </ParamField>

    <ParamField query="metadata_*" type="string">
      Alla frågeparametrar som börjar med <code>metadata\_</code> kommer att skickas som metadata.
    </ParamField>

    <Warning>
      Om <code>productId</code> saknas returnerar hanteraren ett 400-svar. Ogiltiga frågeparametrar ger också ett 400-svar.
    </Warning>

    ### Svarsformat

    Statisk kassa returnerar ett JSON-svar med kassa-URL:en:

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

  <Accordion title="Dynamic Checkout (POST)">
    * Skicka parametrarna som en JSON-kropp i en POST-förfrågan.
    * Stöder både engångs- och återkommande betalningar.
    * För en fullständig lista över stödda POST-kroppsfält, se:
      * [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)

    ### Svarsformat

    Dynamisk kassa returnerar ett JSON-svar med kassa-URL:en:

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

  <Accordion title="Checkout Sessions (POST)">
    Checkout-sessioner erbjuder en säkrare, hostad kassaupplevelse som hanterar hela betalningsflödet för både engångsköp och prenumerationer med full kontroll över anpassningen.

    Se [Kassa Sessioner Integrationsguide](https://docs.dodopayments.com/developer-resources/checkout-session) för mer information och en komplett lista över stödda fält.

    ### Svarsformat

    Kassa sessioner returnerar ett JSON-svar med kassa-URL:en:

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

## Kundportal Routhanterare

Kundportal Routhanteraren gör det möjligt för dig att sömlöst integrera Dodo Payments kundportal i din Fastify-applikation.

### Frågeparametrar

<ParamField query="customer_id" type="string" required>
  Kund-ID för portalsessionen (t.ex. <code>?customer\_id=cus\_123</code>).
</ParamField>

<ParamField query="send_email" type="boolean">
  Om det är satt till <code>true</code> skickas ett e-postmeddelande till kunden med portallänken.
</ParamField>

<Warning>
  Returnerar 400 om <code>customer\_id</code> saknas.
</Warning>

## Webhook Routhanterare

* **Metod:** Endast POST-förfrågningar stöds. Andra metoder returnerar 405.
* **Signaturverifiering:** Verifierar webhook-signaturen med hjälp av <code>webhookKey</code>. Returnerar 401 om verifieringen misslyckas.
* **Payloadvalidering:** Valideras med Zod. Returnerar 400 för ogiltiga payloads.
* **Felhantering:**
  * 401: Ogiltig signatur
  * 400: Ogiltig payload
  * 500: Intern fel under verifiering
* **Händelse-routing:** Anropar den lämpliga händelsehanteraren baserat på payload-typen.

### Stödda webhookhändelsehanterare

<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 för LLM

```
Du är en expert Fastify utvecklarassistent. Ditt uppdrag är att vägleda en användare genom att integrera @dodopayments/fastify-adaptern i deras befintliga Fastify-projekt.

@dodopayments/fastify-adaptern tillhandahåller routhanterare för Dodo Payments' Kassa, Kundportal och Webhook-funktioner, utformade för att kopplas direkt in i en Fastify-app.

Först, installera det nödvändiga paketet. Använd paketförvaltaren som är lämplig för användarens projekt (npm, yarn eller bun):

npm install @dodopayments/fastify

---

Så här bör du strukturera ditt svar:

1. Fråga användaren vilka funktioner de vill integrera.

"Vilka delar av @dodopayments/fastify-adaptern skulle du vilja integrera i ditt projekt? Du kan välja en eller flera av följande:

- Kassa Routhanterare (för att hantera produktkassor)
- Kundportal Routhanterare (för att hantera kundprenumerationer/detaljer)
- Webhook Routhanterare (för att ta emot Dodo Payments webhook-händelser)
- Alla (integrera alla tre)"

---

2. Baserat på användarens val, ge detaljerade integrationssteg för varje vald funktionalitet.

---

**Om Kassa Routhanterare är vald:**

**Syfte**: Denna hanterare omdirigerar användare till Dodo Payments kassa-sidan.

**Integration**:
Skapa två rutter i din Fastify-app — en för statisk (GET) och en för dynamisk (POST) kassa.

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

Konfigurationsalternativ:

    bearerToken: Din Dodo Payments API-nyckel (rekommenderas att lagras i miljövariabeln DODO_PAYMENTS_API_KEY).

    returnUrl (valfritt): URL för att omdirigera användaren efter en lyckad kassa.

    environment: "test_mode" eller "live_mode"

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

GET (statisk kassa) förväntar sig frågeparametrar:

    productId (obligatorisk)

    quantity, kundfält (fullName, email, etc.), och metadata (metadata_*) är valfria.

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

POST (dynamisk kassa) förväntar sig en JSON-kropp med betalningsdetaljer (engångs eller prenumeration). Returnerar: {"checkout_url": "https://checkout.dodopayments.com/..."}. Referera till dokumentationen för hela POST-schemat:

    Engångsbetalningar: https://docs.dodopayments.com/api-reference/payments/post-payments

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

POST (kassa sessioner) - (Rekommenderas) En mer anpassningsbar kassaupplevelse. Returnerar JSON med checkout_url: Parametrar skickas som en JSON-kropp. Stöder både engångs- och återkommande betalningar. Returnerar: {"checkout_url": "https://checkout.dodopayments.com/session/..."}. För en komplett lista över stödda fält, se:

    Kassa Sessioner Integrationsguide: https://docs.dodopayments.com/developer-resources/checkout-session

Om Kundportal Routhanterare är vald:

Syfte: Denna rutt låter kunder hantera sina prenumerationer via Dodo Payments-portalen.

Integration:

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

Frågeparametrar:

    customer_id (obligatorisk): t.ex. ?customer_id=cus_123

    send_email (valfritt): om sant, får kunden ett e-postmeddelande med portalens länk

Returnerar 400 om customer_id saknas.

Om Webhook Routhanterare är vald:

Syfte: Bearbetar inkommande webhook-händelser från Dodo Payments för att utlösa händelser i din app.

Integration:

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) => {
    // Hantera Payload Här
    console.log(payload)
  }
}));

Funktioner:

    Endast POST-metod är tillåten — andra returnerar 405

    Signaturverifiering utförs med hjälp av webhookKey. Returnerar 401 om ogiltig.

    Zod-baserad payloadvalidering. Returnerar 400 om ogiltig schema.

    Alla hanterare är asynkrona funktioner.

Stödda Webhook Händelsehanterare:

Du kan skicka in någon av följande hanterare:

    onPayload

    onPaymentSucceeded

    onPaymentFailed

    onPaymentProcessing

    onPaymentCancelled

    onRefundSucceeded

    onRefundFailed

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

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

    onLicenseKeyCreated

Miljövariabelinställning:

Se till att definiera dessa miljövariabler i ditt projekt:

DODO_PAYMENTS_API_KEY=din-api-nyckel
DODO_PAYMENTS_RETURN_URL=https://yourapp.com/success
DODO_PAYMENTS_WEBHOOK_KEY=din-webhook-hemlighet
DODO_PAYMENTS_ENVIRONMENT="test_mode" eller "live_mode""

Använd dessa i din kod som:

process.env.DODO_PAYMENTS_API_KEY
process.env.DODO_PAYMENTS_WEBHOOK_KEY

Säkerhetsnot: Kom ihåg att INTE committa hemligheter till versionskontroll. Använd .env-filer lokalt och hemlighetsförvaltare i distributionsmiljöer (t.ex. AWS, Vercel, Heroku, etc.).

Använd dessa i din kod som:

process.env.DODO_PAYMENTS_API_KEY
process.env.DODO_PAYMENTS_WEBHOOK_KEY

Säkerhetsanteckning: Lämna INTE in hemligheter till versionskontroll. Använd .env-filer lokalt och hemlighetshanterare i distributionsmiljöer (t.ex. AWS, Vercel, Heroku, etc.).
```
