Skip to main content
The Kotlin SDK gives Kotlin applications typed access to the Dodo Payments REST API. It uses Kotlin types throughout: nullable values for fields that can be missing, Sequence for iterating results, and suspend functions for asynchronous calls.

Installation

Gradle (Kotlin DSL)

Add the dependency to your build.gradle.kts:
build.gradle.kts

Maven

Add the dependency to your pom.xml:
pom.xml
SDK releases add support for API changes. To find the most recent version, check Maven Central.
The SDK requires Java 8 or later. It runs on the JVM and on Android, and it ships ProGuard and R8 keep rules.

Quick Start

Create a client, then create a checkout session:
fromEnv() connects to live mode unless DODO_PAYMENTS_BASE_URL or dodopayments.baseUrl says otherwise. To use test mode, see Test Mode. A test mode API key works only in test mode.
Keep API keys in environment variables or a secrets manager. Never commit them to version control.

Core Features

Coroutines

The async client’s methods are suspend functions that you call from a coroutine.

Null Safety

Fields that can be missing are nullable types, not Optional.

Sequences

On the synchronous client, autoPager() returns a Sequence that fetches more pages as you iterate. On the async client, it returns a Flow.

Immutable Models

Model classes are immutable, and toBuilder() returns a builder for a modified copy.

Configuration

From Environment Variables

fromEnv() reads your settings from environment variables or system properties. System properties take precedence:
The API key comes from DODO_PAYMENTS_API_KEY or dodopayments.apiKey. The webhook signing secret comes from DODO_PAYMENTS_WEBHOOK_KEY or dodopayments.webhookKey, and the base URL from DODO_PAYMENTS_BASE_URL or dodopayments.baseUrl. Create one client and reuse it, because each client has its own connection pool and thread pools. To verify a webhook, pass the raw request body and headers to client.webhooks().unwrap(UnwrapWebhookParams.builder().body(rawBody).headers(headers).build()), where headers is a com.dodopayments.api.core.http.Headers. It checks the signature with your webhook key and returns the parsed event, or throws DodoPaymentsWebhookException. Without headers, unwrap doesn’t verify the signature. client.webhooks().unsafeUnwrap(rawBody) parses the body without verifying it, so use it only for testing. See Webhooks.

Manual Configuration

Set each option on the builder:

Test Mode

To use test mode (https://test.dodopayments.com), call testMode() on the builder:

Timeouts and Retries

By default, the client retries twice and times out after 1 minute. It retries connection errors and responses with status 408, 409, 429, or 500 and above, with exponential backoff. Set the defaults on the client, or pass RequestOptions to a single call:

Common Operations

The examples in this section use the client from Quick Start.

Create a Checkout Session

Create a checkout session, then redirect the customer to the returned checkout URL:
checkoutUrl() returns a nullable String?. Each checkout URL works once and expires after 24 hours. For every session option, see Checkout Sessions.

Create a Product

Create a monthly subscription product priced at $29.99:
price is in the smallest currency unit. discountBps sets the discount in basis points and replaces the deprecated discount field.

Activate License Key

Activate a license key for a device or installation. If the key has reached its activation limit, the API returns 422 and the SDK throws UnprocessableEntityException. An inactive key returns 403 (PermissionDeniedException), and an unknown key returns 404 (NotFoundException):

Handle Subscriptions

Create a subscription, then charge it if it’s an on-demand subscription.
POST /subscriptions (the SDK’s subscriptions().create() method) is deprecated. It still works for existing integrations, but new integrations should create subscriptions through a Checkout Session.
billing requires only country, a two-letter ISO country code. Use AttachExistingCustomer to attach an existing customer, or NewCustomer to create one. charge is for on-demand subscriptions, and productPrice is in the smallest currency unit.

Usage-Based Billing

Record Usage Events

Send a usage event for a customer. Meters that track the event’s eventName aggregate it:
The eventId is the idempotency key, so give each event a unique value. A request accepts up to 1,000 events.

Async Operations

Async Client

The async client has the same methods as the synchronous client, but most of them are suspend functions. Call them from a coroutine:
You can also call client.async() on a synchronous client to get its async version.

Error Handling

For an error status, the SDK throws a subclass of DodoPaymentsServiceException, which has statusCode(), headers(), and body(). The subclasses are BadRequestException (400), UnauthorizedException (401), PermissionDeniedException (403), NotFoundException (404), UnprocessableEntityException (422), RateLimitException (429), InternalServerException (5xx), and UnexpectedStatusCodeException for other statuses, such as 409:
Network failures throw DodoPaymentsIoException, and responses the SDK can’t interpret throw DodoPaymentsInvalidDataException. All SDK exceptions extend DodoPaymentsException.

Functional Error Handling

Use Result for functional error handling:
runCatching catches every exception, including SDK exceptions, and returns them as a failed Result.

Android Integration

The Kotlin SDK is a server SDK. It authenticates with your secret API key, and anyone who has your APK can extract a key compiled into it, so never use it inside an Android app. To take payments in an Android app:
  1. On your server, create the checkout session with this SDK (see Ktor Integration) and return its checkout_url.
  2. In the app, fetch that checkout_url from your server and open it with the Android SDK, which holds no API key.

Response Validation

By default, the SDK throws DodoPaymentsInvalidDataException only when you read a property with an unexpected type. To check the whole response up front, enable validation for a request, or call validate() on a response:

Advanced Features

Proxy Configuration

To send requests through a proxy, pass a java.net.Proxy to the builder:

Temporary Configuration

withOptions returns a client with modified settings that shares the original client’s connection and thread pools. The original client doesn’t change:

Ktor Integration

Create the client once and call it from a route:

Resources

GitHub Repository

Source code, releases, and the full method list.

API Reference

Every endpoint, parameter, and response.

Discord Community

Ask questions and talk with other developers.

Report Issues

Report bugs or request features.

Support

For help with the Kotlin SDK:

Contributing

To contribute, read the contributing guidelines.
Last modified on September 26, 2026