Revenue Connectors · Dodo

Connect Dodo Payments to Admaxxer

Forward Dodo's payment.succeeded webhook to Admaxxer so every successful charge — one-time and subscription renewal — shows up in your revenue attribution, blended MER, and cohort LTV. Five-minute setup, signed via the X-Dodo-Signature or Dodo-Signature header (HMAC-SHA256), visitors stitched via data.metadata.admx_visitor_id.

Open Revenue Settings Back to all connectors

1. Prerequisites

2. Create a Dodo API key

  1. In the Dodo dashboard, go to Settings › API Keys › + Create new key.
  2. Name it Admaxxer Revenue Read.
  3. Permissions: Read payments, Read subscriptions. Nothing else.
  4. Copy the value and paste it into Admaxxer › Revenue Settings › Dodo.

3. Add the webhook endpoint

Dodo will send signed webhook events to a single Admaxxer URL. Replace <YOUR_WEBSITE_ID> with the UUID shown in Revenue Settings.

https://admaxxer.com/api/pixel/webhooks/dodo/<YOUR_WEBSITE_ID>
  1. In the Dodo dashboard, go to Settings › Webhooks › + Add endpoint.
  2. Endpoint URL: paste your Admaxxer webhook URL.
  3. Events:
    • payment.succeeded
  4. Recommended additional: payment.refunded, payment.failed (for monitoring).
  5. Save. Dodo reveals a webhook secret.
  6. Copy the secret and paste it into Admaxxer Revenue Settings › Dodo › Webhook signing secret.

The signing secret is what makes the X-Dodo-Signature or Dodo-Signature header verifiable. Without it, Admaxxer rejects every inbound webhook with 401 invalid_signature.

4. Stamp the visitor ID on every payment

Pass metadata on every Payment creation. The pixel exposes window.admx.getVisitorId() for client-side reads, and a 1p cookie (admx_vid) for server-side reads.

// Server-side, dodo-payments SDK or fetch
const payment = await fetch('https://api.dodopayments.com/payments', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + process.env.DODO_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 4900,
    currency: 'USD',
    metadata: {
      admx_visitor_id: req.cookies['admx_vid'] || ''
    },
    customer_email: 'jane@example.com'
  })
}).then(r => r.json());

The metadata object travels with the Payment record and is included as data.metadata on every webhook event for that payment.

5. Verify the connection

  1. In Dodo, go to Settings › Webhooks, select your Admaxxer endpoint, and click Send test event.
  2. Choose payment.succeeded and send.
  3. In Admaxxer, open Revenue Settings. The "Last 50 webhook deliveries" panel shows the test with status ok.
  4. Run a real test payment in Dodo's sandbox. Inspect the resulting Payment and confirm metadata.admx_visitor_id is non-empty.
  5. Within 3 seconds, the order appears in the Admaxxer attribution dashboard, joined to the visitor's acquisition source.

6. Troubleshooting

Webhook returns 401 invalid_signature
Signing secret mismatch. Re-copy the webhook secret from the Dodo webhook screen into Admaxxer Revenue Settings. Don't paste your API key — only the webhook signing secret validates inbound payloads.
Order appears as unattributed
data.metadata.admx_visitor_id was empty on the Payment. Confirm the metadata was set when calling Dodo's API. Inspect the Payment in the Dodo dashboard to verify the metadata field contains admx_visitor_id.
Recurring charges not attributing back to the original visitor
Each renewal-style payment must include the same metadata.admx_visitor_id. If you store the visitor ID on the customer or subscription record at first-purchase time, copy it onto every subsequent Payment object you create.
Refunds not subtracting from MER
Add payment.refunded to the same endpoint. Admaxxer treats refunds as negative revenue events linked to the original payment.

Frequently asked

Why does the visitor field include data.metadata instead of just metadata?
Dodo's webhook payload structure wraps the actual event object in a top-level data envelope, so all event fields — including metadata — are reachable at data.<field>. The Admaxxer Dodo connector reads exactly data.metadata.admx_visitor_id; setting metadata.admx_visitor_id at the top level (without the data wrapper) won't be found.
What versions of the Dodo API does this support?
The Admaxxer Dodo connector targets Dodo's current REST API and the data-envelope webhook payload format. If Dodo introduces a new API version, we accept both shapes during the transition window — you don't need to coordinate a Dodo API upgrade with an Admaxxer redeploy.
How do I add metadata on a Dodo Payment?
When creating a Payment via the Dodo API, pass metadata: { admx_visitor_id: '<visitor-id>' } in the request body. The metadata object is preserved on the Payment record and included on the data.metadata field of every webhook event for that payment. The Admaxxer pixel exposes window.admx.getVisitorId() to retrieve the value.
Why are there two possible signature header names?
Dodo's webhook implementation uses X-Dodo-Signature in newer integrations and Dodo-Signature in older ones. Admaxxer accepts either name and verifies with the same HMAC-SHA256 algorithm. You don't need to configure anything — we read whichever header Dodo sends.
What about subscription billing?
If you use Dodo for recurring billing, each successful charge fires its own payment.succeeded event with a fresh payment ID and a subscription_id reference (when applicable). Admaxxer records each as an independent revenue event linked back to the visitor who created the original subscription, so cohort LTV correctly accumulates.

Next steps