# Connect Dodo (https://www.getfounderhq.com/docs/analytics/revenue/connect-dodo)

Connect Dodo Payments so FounderHQ records every payment, refund, dispute, and
subscription change. The recommended path is a read-only API key — there is no
webhook to configure, and revenue appears within a few minutes.

<Callout title="Before you start">
  You need a [FounderHQ brand](/analytics/getting-started) with the Events SDK
  installed, and a live Dodo Payments business you can open the dashboard for.
</Callout>

## Which should I choose?

| Mode                 | Choose it when                             | Your revenue appears |
| -------------------- | ------------------------------------------ | -------------------- |
| **Paste an API key** | You want the simplest setup                | Within a few minutes |
| **Webhook**          | You want to configure every event yourself | In seconds           |

## Paste an API key (recommended)

1. In FounderHQ, open **Settings → Integrations → Revenue**.
2. Choose Dodo Payments and the brand. Select **Paste an API key
   (recommended)**.
3. Open [Dodo API Keys](https://app.dodopayments.com/developer/api-keys) and
   choose **Add API Key**.
4. Leave **Enable write access** off. This makes the key read-only.
5. Copy the live `dp_live_` key into FounderHQ and connect.

FounderHQ checks the key against Dodo's live API and binds the business it
belongs to. A test-mode key is refused. The key is encrypted, never included
in revenue evidence, and can be revoked from Dodo anytime.

There is no webhook setup. FounderHQ checks Dodo every few minutes and reads
payments, refunds, subscriptions, and disputes. Use **Sync now** when you need
an immediate refresh.

## Webhook (manual)

### 1. Create the connection in FounderHQ

In FounderHQ, open **Settings → Integrations → Revenue**. Choose Dodo Payments,
the brand, then select **Webhook**.

Do not enter a business ID. Dodo puts the business on every signed event, and
FounderHQ binds it from the first verified event. After that, events from any
other business are rejected.

FounderHQ gives you a webhook URL:

```text
https://app.getfounderhq.com/api/hooks/payments/dodo/CONNECTION_ID
```

### 2. Add the endpoint in Dodo and select the events

```text
payment.succeeded
refund.succeeded
refund.failed
subscription.active
subscription.cancelled
subscription.expired
subscription.failed
subscription.on_hold
subscription.plan_changed
subscription.renewed
subscription.updated
dispute.accepted
dispute.cancelled
dispute.challenged
dispute.expired
dispute.lost
dispute.opened
dispute.won
```

FounderHQ ignores any other event type.

### 3. Paste the signing secret back

Dodo mints the signing secret, not FounderHQ. Copy it from the Dodo endpoint
and paste it into the FounderHQ connection.

When you rotate the secret later, FounderHQ accepts both the old and the new
secret for 24 hours. That matches Dodo's own rotation window, so no event is
lost mid-rotation.

### 4. Send a test event

Send a signed test event from Dodo. FounderHQ verifies the signature, binds
your business ID, and marks the connection **Connected**.

## Attach attribution at checkout creation

Dodo carries your metadata from checkout into the payment. Build it with the
Node SDK and pass it as the `metadata` object when you create the payment or
subscription.

```ts
// app/api/dodo-checkout/route.ts
import { checkoutMetadata } from "@founderhq/events-node";

export async function POST(request: Request) {
  const { identity, productId } = await request.json();
  const metadata = checkoutMetadata({
    anonymousId: identity.fhq_anonymous_id,
    sessionId: identity.fhq_session_id,
  });

  // Pass `metadata` as the metadata field of your Dodo checkout call.
  return Response.json({ productId, metadata });
}
```

The browser supplies `identity` from `founderhq.checkoutMetadata()`. See
[checkout metadata and payment links](/analytics/revenue/checkout-metadata-and-payment-links).

Renewals carry no browser session. FounderHQ binds the Dodo customer and
subscription on the first payment and resolves renewals through that binding.

## What creates revenue, and what does not

| Dodo observation    | Effect in FounderHQ                                                                 |
| ------------------- | ----------------------------------------------------------------------------------- |
| Successful payment  | Creates revenue. This covers first payments, renewals, and Indian recurring debits. |
| Successful refund   | Subtracts revenue.                                                                  |
| Subscription change | Updates subscription state and MRR only. It never creates revenue.                  |
| Dispute change      | Stored as evidence. It does not change revenue today.                               |

Dodo fires a renewal event alongside the first payment. That is why lifecycle
events never create money on their own. The API-key path follows the same rule
when it reconstructs the current resource state.

Selling in India? FounderHQ stores both the charged total and the settlement
amount. Channel revenue uses the charged total.

## Verify

### API key

1. The connection shows **Connected** as soon as Dodo verifies the key.
2. Open Revenue after the first sync. Existing recent payments appear there.
3. A new live payment appears with the channel that brought the buyer, under
   **Introduced by** and **Closed by**.

### Webhook

1. Send a signed test event from Dodo. The connection shows **Connected**.
2. Take a payment through your checkout.
3. In FounderHQ, open Revenue and inspect its attribution.

## Troubleshoot

### FounderHQ asks for a live-mode API key

The pasted key belongs to Dodo test mode. Open the live Dodo dashboard and
create a read-only key there.

### FounderHQ says the key belongs to another Dodo business

The connection is already bound to another business. Use a key for that
business, or create a separate connection for the other one.

### Dodo shows "Invalid signature"

The pasted webhook secret is wrong or was rotated more than 24 hours ago. Copy
the current secret from Dodo and paste it again.

### The webhook connection stays on "Waiting for test"

No signed event has arrived yet. Send a test event from the Dodo endpoint.
