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

# Build an App

> Build an app for the Dodo Payments App Marketplace. Create the app, run the OAuth authorization code flow with PKCE, call the API for each installed business, receive webhooks, and submit the app for review.

## Overview

An app is a program that a merchant installs into their Dodo Payments business. After the merchant approves the scopes that the app requests, the app calls the Dodo Payments API for that business and receives webhooks about it.

This guide shows how to:

* Create an app and get its credentials.
* Run the OAuth authorization code flow with PKCE.
* Keep tokens fresh.
* Receive and verify webhooks.
* Submit the app for review and list it publicly.

> [!NOTE]
>
> The App Marketplace is available only to businesses that have the `app_marketplace` feature enabled. Testers need the feature enabled too.

## Create an App

**1. Open the Apps Page**

In the dashboard, open **Apps**, then the **Created** tab, and select **Create app**.

**2. Fill In the App Details**

Set the app name, the redirect URIs, the scopes the app needs, and the events it subscribes to. Write a short reason for each scope. The merchant reads these reasons on the consent screen.

**3. Copy the Credentials**

Copy the client ID and the client secret (it starts with `dodo_cs_`). The dashboard shows the secret one time.

Redirect URIs must use HTTPS, must match exactly, and are limited to 10 per app. A public app cannot use a loopback address or a private IP address.

> [!WARNING]
>
> If you rotate the client secret, the old secret stops working immediately. Update your servers before you rotate.

## Live and Test Installs

Live and test installs are separate. A merchant installs your app once in live mode and once in test mode. Each install has its own tokens, its own scopes, and its own webhooks.

Set `resource` to `https://test.dodopayments.com` for a test install or `https://live.dodopayments.com` for a live install. The API host for the install is the same URL. The examples on this page use the test host. For a live install, use the live host.

Every authorization request must include one `resource`. A request with no `resource` fails with `invalid_target`.

## Authorize a Business

The app uses the OAuth 2.0 authorization code flow with PKCE (`S256`) and the client secret. The authorization server is `https://auth.dodopayments.com`.

**1. Create a PKCE Pair**

Create a random `code_verifier`. Compute `code_challenge` as the Base64URL-encoded SHA-256 hash of the verifier.

**2. Send the Merchant to the Authorize Endpoint**

```text theme={null}
https://auth.dodopayments.com/oauth2/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
  &scope=payments%3Aread%20customers%3Aread
  &resource=https%3A%2F%2Ftest.dodopayments.com
  &code_challenge=CODE_CHALLENGE
  &code_challenge_method=S256
  &state=RANDOM_STATE
```

The merchant signs in. An owner or an admin of the business approves all scopes or none. The merchant sees the reason that you wrote for each scope.

**3. Receive the Code**

Dodo Payments redirects to your `redirect_uri` with `code` and `state`. Check that `state` matches the value that you sent.

**4. Exchange the Code for Tokens**

Send the client ID and secret with HTTP Basic authentication.

```bash theme={null}
curl https://auth.dodopayments.com/oauth2/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri="https://app.example.com/callback" \
  -d code_verifier="$CODE_VERIFIER"
```

The response holds `access_token`, `refresh_token`, `expires_in`, and `scope`.

**5. Call the API**

```bash theme={null}
curl https://test.dodopayments.com/payments \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

A token works only for its own business and its own mode, and only for the granted scopes. A call outside the granted scopes returns `403`.

> [!NOTE]
>
> Activation is asynchronous. Your app can receive the authorization code and call the API before the install is `active`, and before the `app.installed` webhook arrives. Do not wait for `app.installed` to start the token exchange. Use it to record the install.

### Token Lifetimes

| Token | Lifetime |
| - | - |
| Access token | 1 hour |
| Refresh token | 365 days, rolling. Each refresh gives a new refresh token. |

Refresh with the same Basic authentication:

```bash theme={null}
curl https://auth.dodopayments.com/oauth2/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token="$REFRESH_TOKEN" \
  -d resource="https://test.dodopayments.com"
```

Store the new refresh token and discard the old one. If you use an old refresh token a second time, Dodo Payments revokes the grant, and the install receives `app.uninstalled`.

### Uninstall and Revocation

A merchant owner or admin can uninstall the app at any time. The install stays active if the person who installed it leaves the business.

Revocation takes effect within 2 minutes. During that time, a token that was revoked can still work. After that time, the API returns `401`. You can also revoke a token yourself at `https://auth.dodopayments.com/oauth2/revoke`.

## Scopes

A scope has the form `resource:read` or `resource:write`, for example `payments:read` or `refunds:write`. The dashboard lists the scopes that you can assign when you create the app.

Scopes that give access to money movement or customer data get extra attention in review. Request only the scopes that the app uses.

If you add a scope later, existing installs keep their old scopes and the merchant sees a banner to approve the new scopes. Calls that need the new scope fail until the merchant approves.

## Webhooks

An app has one webhook endpoint for live installs (`webhook_url`) and one for test installs (`webhook_url_test`). Test events are sent only if you set `webhook_url_test`. Without it, the app page shows a warning.

### Which Events an App Receives

An app receives an event only if both of these are true:

1. The app subscribed to the event type.
2. The install granted the read scope of the resource that the event describes.

| Event family | Required scope |
| - | - |
| `payment.*` | `payments:read` |
| `refund.*` | `refunds:read` |
| `dispute.*` | `disputes:read` |
| `subscription.*` | `subscriptions:read` |
| `customer.*` | `customers:read` |
| `license_key.*` | `license_keys:read` |

The dashboard shows the full list for each scope when you choose events.

The app always receives these events for its own installs, with no scope check: `app.installed`, `app.installation.updated`, and `app.uninstalled`.

> [!WARNING]
>
> `payment.*` events need only `payments:read`, and they carry the full payload, including the customer name and email. The consent screen tells the merchant that payment access includes customer contact data. Handle this data under your privacy policy.

### Payload

Every webhook has these fields at the top level:

```json theme={null}
{
  "livemode": true,
  "business_id": "bus_123",
  "installation_id": "ains_123",
  "app_id": "app_123",
  "type": "payment.succeeded",
  "data": {}
}
```

| Field | Meaning |
| - | - |
| `livemode` | `true` for a live install, `false` for a test install |
| `business_id` | The business that installed the app |
| `installation_id` | The install that the event belongs to |
| `app_id` | Your app |
| `type` | The event type |
| `data` | The event data. It has the same shape as the merchant webhook for that event. |

### Verify the Signature

Dodo Payments signs each message with Svix. Verify the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers against the raw request body, with the signing secret of your endpoint.  The app webhook uses the same Svix headers and verification steps as a merchant webhook. See [Webhooks](https://docs.dodopayments.com/developer-resources/webhooks.md) for code examples in each language.

Return a `2xx` response quickly. Use `webhook-id` to ignore a message that you already processed.

## Privacy Webhooks

An app that has `customers` scopes must handle three privacy events before it can be listed publicly:

* `customer.data_request`
* `customer.redact`
* `business.redact`

Dodo Payments sends each event to your `webhook_url`, with the same payload fields as other app webhooks. When you receive one, delete or anonymize the data that the event names, then return a `2xx` response. Finish each request within 30 days. `business.redact` is sent 48 hours after the app is uninstalled.&#x20;

## Review and Listing

A private app can be installed by its own business only. To list an app publicly, select **Make public** and submit it for review.

* The review target is 5 business days.
* Reviewers check the test credentials, redirect URIs, scopes and their reasons, the privacy policy and support URLs, the name and icon, and that your webhook endpoint returns `2xx` for a test event.
* If a reviewer rejects the app, you see the reason. Fix the issues and submit again.
* A reviewer can suspend an app. A suspended app is hidden, its tokens are revoked, and its webhooks stop.

### Change a Live App

When you edit a live app, the change goes to review. The live version, with its approved scopes, redirect URIs, and events, stays active until the change is approved. A rejected change does not affect the live version.

> [!NOTE]
>
> You cannot test a pending redirect URI. The authorization server uses the approved redirect URIs only. To test a new redirect URI, use a separate private app.

### Test Before You List

Use the test link on the app page to let up to 25 other businesses install a private app or an app in review. Testers need the `app_marketplace` feature enabled. The app shows a **Test app** badge to them. If you rotate the test link, new businesses cannot join with the old link.

## Rate Limits

Each pair of app and business is limited to 20 requests each second and 120 requests each minute. A call over the limit returns `429`. Retry with a back-off.

## Next Steps

> [card] [Webhooks](https://docs.dodopayments.com/developer-resources/webhooks.md)
>
> Signature verification and retries.

> [card] [API reference](https://docs.dodopayments.com/api-reference/introduction.md)
>
> All endpoints that an app can call.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.