Skip to Content
⭐ CraftJS is open source. Star on GitHub →
DocsPayments API

Payments API

The Payments API handles subscriptions, checkouts, and billing management.

Create Checkout

Create a checkout session for subscription purchase.

POST /api/checkout

Request Body:

{ "planId": "pro" }

Parameters:

FieldTypeRequiredDescription
planIdstringYesPlan ID (pro, enterprise)

Response:

{ "url": "https://checkout.dodopayments.com/session_123", "sessionId": "session_123" }

Usage:

const response = await fetch("/api/checkout", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ planId: "pro" }), }) const { url } = await response.json() window.location.href = url // Redirect to checkout

Billing Portal

Get a link to the customer billing portal.

POST /api/billing/portal

Response:

{ "url": "https://billing.dodopayments.com/portal_123" }

The billing portal allows users to:

  • View invoices
  • Update payment method
  • Cancel subscription
  • Change plan

Subscription Status

Get the current user’s subscription.

GET /api/billing/subscription

Response:

{ "id": "sub_123", "plan": "pro", "status": "active", "currentPeriodStart": "2024-01-01T00:00:00.000Z", "currentPeriodEnd": "2024-02-01T00:00:00.000Z", "cancelAtPeriodEnd": false }

Status Values:

StatusDescription
activeSubscription is active
past_duePayment failed, grace period
canceledSubscription canceled
trialingIn trial period

Cancel Subscription

Request subscription cancellation.

POST /api/billing/cancel

Request Body:

{ "reason": "Too expensive", "feedback": "Optional additional feedback", "cancelImmediately": false }

Response:

{ "success": true, "cancelAtPeriodEnd": true, "currentPeriodEnd": "2024-02-01T00:00:00.000Z" }

By default, subscriptions cancel at the end of the billing period. Set cancelImmediately: true for immediate cancellation (no refund).

Resume Subscription

Resume a canceled subscription before period ends.

POST /api/billing/resume

Response:

{ "success": true, "status": "active" }

Change Plan

Upgrade or downgrade subscription.

POST /api/billing/change-plan

Request Body:

{ "planId": "enterprise" }

Response:

{ "success": true, "plan": "enterprise", "prorationAmount": 50.00, "effectiveDate": "2024-01-15T00:00:00.000Z" }

Payment History

Get user’s payment history.

GET /api/billing/payments

Response:

{ "payments": [ { "id": "pay_123", "amount": 1900, "currency": "usd", "status": "succeeded", "createdAt": "2024-01-01T00:00:00.000Z", "invoiceUrl": "https://..." } ], "hasMore": false }

Plans

Get Available Plans

GET /api/billing/plans

Response:

{ "plans": [ { "id": "free", "name": "Free", "price": 0, "interval": "month", "features": [ "100 AI requests/month", "10MB storage", "Basic support" ], "limits": { "aiRequests": 100, "storage": 10485760 } }, { "id": "pro", "name": "Pro", "price": 1900, "interval": "month", "features": [ "10,000 AI requests/month", "10GB storage", "Priority support", "Advanced analytics" ], "limits": { "aiRequests": 10000, "storage": 10737418240 } }, { "id": "enterprise", "name": "Enterprise", "price": 9900, "interval": "month", "features": [ "Unlimited AI requests", "100GB storage", "24/7 dedicated support", "Custom integrations", "SSO" ], "limits": { "aiRequests": -1, "storage": 107374182400 } } ] }

Client Usage

"use client" import { useQuery, useMutation } from "@tanstack/react-query" export function useBilling() { const subscription = useQuery({ queryKey: ["subscription"], queryFn: () => fetch("/api/billing/subscription").then((r) => r.json()), }) const checkout = useMutation({ mutationFn: async (planId: string) => { const res = await fetch("/api/checkout", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ planId }), }) const { url } = await res.json() window.location.href = url }, }) const openPortal = useMutation({ mutationFn: async () => { const res = await fetch("/api/billing/portal", { method: "POST" }) const { url } = await res.json() window.location.href = url }, }) return { subscription, checkout, openPortal } }

Webhooks

Payment events are delivered via webhooks to /api/webhooks/dodo. See Webhook Handling for details.

Events:

EventDescription
payment.succeededPayment successful
payment.failedPayment failed
subscription.createdNew subscription
subscription.updatedPlan change
subscription.canceledSubscription canceled
subscription.past_duePayment overdue

Error Codes

CodeDescription
PLAN_NOT_FOUNDInvalid plan ID
ALREADY_SUBSCRIBEDAlready has this plan
NO_SUBSCRIPTIONNo active subscription
PAYMENT_REQUIREDPayment method needed
CHECKOUT_FAILEDCheckout creation failed
Last updated on