DocsAPI › Webhooks

Webhooks

District Seal receives webhook events from Dodo Payments to keep subscription state synchronized. This page documents the endpoint, the signature verification scheme, and the events that are processed.

Endpoint

POST https://districtseal.com/api/webhooks/dodo

This endpoint is only called by Dodo Payments. It is not designed for direct use by customers or third-party integrations.

Signature verification

Dodo Payments delivers webhooks using the Svix signature scheme. Every incoming request carries three headers:

HeaderPurpose
webhook-idUnique message identifier
webhook-timestampUnix epoch of the delivery attempt
webhook-signatureHMAC-SHA256 signature, prefixed with v1,

District Seal verifies the signature on every request as follows:

  1. Read the signing secret from the environment.
  2. Strip the whsec_ prefix and base64-decode the secret.
  3. Construct the signed payload as {msg_id}.{timestamp}.{body}.
  4. Compute an HMAC-SHA256 over that payload using the decoded secret.
  5. Base64-encode the result and compare it to the value after v1, in the header.
  6. If the signature does not match, reject with HTTP 401 and do not process the event.
Unsigned requests are rejected. District Seal does not accept webhook events without a valid signature. Requests with missing or mismatched signatures return HTTP 401 Unauthorized and are discarded.

Events processed

Event typeAction taken
payment.succeededFor PAYG products, increments the user's signature_credits by the amount purchased. For subscription products, upgrades the plan.
subscription.activeSets the user's plan to the corresponding tier (Pro, Firm).
subscription.renewedNo-op if the plan is unchanged.
subscription.cancelledDowngrades the user to the Free plan at the end of the current billing period.
subscription.expiredDowngrades immediately.
subscription.failedFlags the account as past due. A grace period applies before downgrade.

Metadata conventions

Every subscription and one-time payment created by District Seal includes a metadata object:

{
  "metadata": {
    "user_id": "41",
    "plan": "pro"
  }
}

The plan field is pro, firm, or payg. When the webhook fires, the handler looks up the user by the email in the event, then applies the plan or credit change.

Retries and idempotency

Dodo Payments retries failed webhooks with exponential backoff. Because retries may occur, the handler is written to be idempotent: applying the same event twice does not double-credit an account. If you are building an integration that consumes District Seal webhooks, follow the same rule — treat the webhook-id as an idempotency key.

Testing

Dodo Payments provides a webhook replay feature in their dashboard for both test mode and live mode. When testing, use the replay feature rather than crafting your own requests — the signature scheme uses a shared secret and manual requests will fail verification.

District Seal is a product of NEXSIM LLC, Montana, United States.

API support: support@districtseal.com

Back to documentation