Skip to main content
The @dodopayments/astro package gives your Astro project three endpoint handlers. Checkout returns checkout URLs, CustomerPortal sends a customer to the Customer Portal, and Webhooks verifies webhook events and routes them to your code.

Checkout Handler

Create checkout URLs with static, dynamic, and checkout session flows.

Customer Portal

Let customers manage their subscriptions and details.

Webhooks

Receive and process Dodo Payments webhook events.

Installation

1

Install the Package

Run this command in your project root:
The package lists Astro 4 or 5, and zod 3.25 or later, as peer dependencies.
2

Set Up Environment Variables

Create a .env file in your project root. Create the API key under Developer → API Keys. Add your webhook endpoint under Developer → Webhooks, and copy its Signing secret into DODO_PAYMENTS_WEBHOOK_KEY:
DODO_PAYMENTS_RETURN_URL is where customers land after checkout. If you don’t pass an environment, the handlers use live_mode. A test mode API key works only with test_mode.
Never commit your .env file or secrets to version control.

Route Handler Examples

The examples are Astro server endpoints in src/pages/api/. Endpoints that call Dodo Payments must render on demand, so add a server adapter to your Astro project. In Astro’s default static output mode, endpoints render at build time, so each example exports prerender = false to render the endpoint on each request instead.
Use this handler to add Dodo Payments checkout to your app. The GET handler serves static checkout. The POST handler serves checkout sessions, or dynamic checkout when you set type: "dynamic". An endpoint file can export only one POST handler, so the dynamic checkout example assumes you set type: "dynamic".

Checkout Route Handler

The checkout handler supports all three ways to take payments with Dodo Payments:
  • Static Payment Links: Shareable URLs that collect payments without code.
  • Dynamic Payment Links: Payment links you generate with custom details. They use deprecated endpoints.
  • Checkout Sessions: Hosted checkout with a product cart, customer details, and customization options. This is the recommended flow.
Checkout takes these options: The handler serves static checkout for GET requests. For POST requests, it creates a dynamic payment link when type is dynamic, and a checkout session otherwise.

Supported Query Parameters

string
required
Product identifier, for example ?productId=pdt_nZuwz45WAs64n3l07zpQR.
integer
default:"1"
Quantity of the product.
string
Customer’s full name. Ignored if firstName or lastName is provided.
string
Customer’s first name.
string
Customer’s last name.
string
Customer’s email address.
string
Customer’s country, as an ISO 3166-1 alpha-2 code.
string
Customer’s street address.
string
Customer’s city.
string
Customer’s state or province.
string
Customer’s ZIP or postal code.
boolean
Set to true to disable the full name field.
boolean
Set to true to disable the first name field.
boolean
Set to true to disable the last name field.
boolean
Set to true to disable the email field.
boolean
Set to true to disable the country field.
boolean
Set to true to disable the address line field.
boolean
Set to true to disable the city field.
boolean
Set to true to disable the state field.
boolean
Set to true to disable the ZIP code field.
string
Payment currency, for example USD.
boolean
default:"true"
Show or hide the currency selector.
number
Fixes the amount charged, in major currency units, for example 12.5 for $12.50. Works with Pay What You Want products only, and is ignored if it’s below the product’s minimum price.
boolean
default:"true"
Show or hide the discounts section.
string
Any query parameter that starts with metadata_ is passed to checkout as metadata, for example metadata_orderId=123.
A disable flag takes effect only when the matching field has a value, for example email with disableEmail=true. The handler adds returnUrl from its config to the link as redirect_url.
If productId is missing, the handler returns a 400 response. Invalid query parameters, or a product that doesn’t exist in your account, also return 400.

Response Format

Static checkout returns a JSON response with the checkout URL. In test mode, the URL uses test.checkout.dodopayments.com:
  • Send the parameters as a JSON body in a POST request.
  • Supports both one-time and recurring payments. The handler retrieves the product, then creates a subscription if the product is recurring and a one-time payment otherwise.
  • The body needs billing (with street, city, state, country, and zipcode) and customer, plus product_id or product_cart. Subscriptions need product_id.
  • For every supported body field, see:
Dynamic checkout proxies the deprecated POST /payments and POST /subscriptions endpoints. It keeps working for existing integrations, but new integrations should use checkout sessions.

Response Format

Dynamic checkout returns a JSON response with the payment link as the checkout URL:
Checkout sessions create a hosted checkout for one-time purchases and subscriptions, with full control over customization. product_cart is the only required field, and it needs at least one product. If the body has no return_url, the handler uses returnUrl from its config.Each checkout_url works once and expires after 24 hours, or after 15 minutes when you pass confirm: true. A session created with payment_method_id returns no checkout_url, so the handler responds with 400.For more details and every supported field, see the Checkout Sessions Integration Guide.

Response Format

Checkout sessions return a JSON response with the checkout URL:

Customer Portal Route Handler

The Customer Portal route handler creates a Customer Portal session for the customer you pass and redirects the browser to it. CustomerPortal takes the same bearerToken and environment options as Checkout.
The handler doesn’t check who is calling it. Anyone who requests it with a customer ID gets that customer’s portal. Protect the route with your own authentication, and pass only the signed-in user’s customer ID.

Query Parameters

string
required
The customer ID for the portal session, for example ?customer_id=cus_123.
boolean
If set to true, Dodo Payments also emails the portal link to the customer.
The handler returns 400 if customer_id is missing, and 500 if the portal session can’t be created.

Webhook Route Handler

The webhook route handler verifies each request with your webhook secret, passed as webhookKey, before it runs your code:
  • Method: Only POST requests are supported. Other methods return 405.
  • Signature Verification: Verifies the webhook-id, webhook-timestamp, and webhook-signature headers with webhookKey, following the Standard Webhooks specification. Returns 401 if verification fails.
  • Payload Validation: Validates the payload with Zod. Returns 400 for an invalid payload.
  • Error Handling:
    • 401: Invalid signature
    • 400: Invalid payload
    • 500: Internal error during verification
  • Event Routing: Calls onPayload for every event, then the handler for the event’s type, and returns 200.
The adaptor doesn’t catch errors thrown in your handlers. They propagate to Astro, and the request fails.

Supported Webhook Event Handlers

Every handler is optional and async, and receives the verified payload for its event type:
For what each event means, see the Webhook Event Guide.

Prompt for LLM

Copy this prompt into your AI coding assistant to have it add the adaptor to your project. To give your agent the Dodo Payments docs and skills as well, install the Agent Plugin.
Last modified on September 25, 2026