Callbacks are available on API version 3.0 only, and must be enabled for your project. Contact your Mixpanel representative to request access.
Subscribing
Passstatus_callback_urls when you create the request. Every URL you name receives its own copy of every callback.
Create a deletion with callbacks
Mixpanel does not generate a
subject_request_id for you. It must be unique within your project.
It is echoed on every callback and on the status endpoint’s response. Correlate on it rather than on Mixpanel’s tracking_id.
The callback request
Mixpanel sends an HTTPPOST with a JSON body and these headers:
Return
202 Accepted once the signature validates, and 403 Forbidden if it does not, which is what OpenDSR §8.8 asks for. Mixpanel treats any 2xx as delivered; any other response, a timeout, or a TLS failure is a failed delivery and is retried.
Example callback
Completed retrieval
Every field is always present.
results_url is null rather than omitted when it does not apply.
Extensions
Everything underextensions is Mixpanel’s own, not part of OpenDSR. A subscriber that ignores this object entirely still works.
Verifying the signature
Most frameworks parse the body before your handler runs. Userequest.get_data() in Flask, express.raw() in Express, request.body in Django, or a ContentCachingRequestWrapper in Spring.
First, reject the callback unless X-OpenDSR-Processor-Domain is exactly opendsr.mixpanel.com. Compare that header against a value you have hardcoded — never treat it as an instruction about which certificate to fetch.
X-OpenDSR-Signature is a base64-encoded RSA signature (PKCS#1 v1.5, SHA-256) over the raw body. Verify it against the public key from Mixpanel’s certificate.
Fetch the certificate once from https://opendsr.mixpanel.com/v1/certificate.pem and store it; do not fetch it per callback. When you fetch it, confirm it chains to a trusted authority, was issued to opendsr.mixpanel.com, and has not expired.
status_callback_url in the body matches the endpoint the request arrived on. OpenDSR includes this step so that a valid callback captured from one of your endpoints cannot be replayed against another.
Certificate renewal
Mixpanel’s certificate is reissued periodically, but the keypair does not change across renewals. Extract and pin the public key rather than the certificate, and renewals require no action from you. If you pin the certificate itself, refresh your copy before it expires.There is no timestamp or nonce in the body, so a captured callback and its signature stay valid indefinitely. A retrieval callback carries a working
results_url — treat a stored body as sensitive and keep it out of your logs.Status vocabulary
request_status is always one of OpenDSR’s four values. Branch on this field.
OpenDSR defines no failure status. A request that errors reports
cancelled — the only terminal value that does not assert fulfilment — and extensions["opendsr.mixpanel.com"].status reads failed. Check that field if you need to distinguish a genuine cancellation from an error.
The first callback arrives shortly after you create the request, while it is still pending. Use it to confirm your endpoint is reachable and your signature verification works against a real body.
Delivery semantics
At-least-once. A retry sends the identical body with the identical signature. Deduplicate on the body, or on the pair ofsubject_request_id and request_status. An exactly-once assumption will double-process.
Retry cadence. Deliveries are attempted every 15 minutes, which is also how quickly a status change reaches a healthy endpoint. A failed delivery is retried on the next cycle.
When Mixpanel stops. Retries stop 90 days after the request was created — longer than the 30-day expected_completion_time, so a request that misses its deadline still delivers its completion callback. After 90 days you receive nothing further.
The status endpoint remains the source of truth throughout. If a callback you expected has not arrived, poll it.
Discovery
Mixpanel publishes an OpenDSR discovery document athttps://opendsr.mixpanel.com/v1/discovery. It needs no authentication.
GET /v1/discovery
controller_customer_id with format raw is the identity type Mixpanel accepts: it corresponds to the distinct_id you already use. The other identity types OpenDSR lists are device and advertising identifiers, which Mixpanel does not resolve requests by.
Limitations
Mixpanel’s callbacks are OpenDSR-aligned, not a full OpenDSR implementation. Field names, status vocabulary, signing and discovery follow the specification, but Mixpanel does not servePOST /v1/requests. Create requests through the endpoints above instead.