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.
1. Prerequisites
- An active Dodo Payments account.
- The Admaxxer pixel installed on the site that creates Dodo payments. See the install index.
- An Admaxxer workspace with the website registered. Your Website ID is at Revenue Settings.
- Permission to create API keys and webhook endpoints in your Dodo dashboard.
2. Create a Dodo API key
- In the Dodo dashboard, go to Settings › API Keys › + Create new key.
- Name it Admaxxer Revenue Read.
- Permissions: Read payments, Read subscriptions. Nothing else.
- 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>
- In the Dodo dashboard, go to Settings › Webhooks › + Add endpoint.
- Endpoint URL: paste your Admaxxer webhook URL.
- Events:
payment.succeeded
- Recommended additional:
payment.refunded,payment.failed(for monitoring). - Save. Dodo reveals a webhook secret.
- 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
- In Dodo, go to Settings › Webhooks, select your Admaxxer endpoint, and click Send test event.
- Choose
payment.succeededand send. - In Admaxxer, open Revenue Settings. The "Last 50 webhook deliveries" panel shows the test with status
ok. - Run a real test payment in Dodo's sandbox. Inspect the resulting Payment and confirm
metadata.admx_visitor_idis non-empty. - 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_idwas 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 containsadmx_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.refundedto 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
- All revenue connectors — back to the hub.
- Stripe, Paddle, Lemon Squeezy, Polar, WooCommerce, Shopify.
- Install the Admaxxer pixel — required for visitor stitching.
- Analytics docs — how Tinybird pipes consume revenue events.