Skip to main content
Formation is asynchronous. Rather than polling, subscribe to webhook events to learn when a formation progresses and when documents become available.

Setup

1

Get your signing secret

doola provisions your tenant and generates your webhook signing secret. It is shown once at creation, so store it securely. Email engineering@doola.com to get set up or to rotate it.
2

Configure your endpoint

Set your webhook URL in the doola Partner Portal. The URL must be HTTPS. Each environment has its own tenant, so configure sandbox and production separately.

Verifying the signature

doola sends a POST with an X-Doola-Signature header: an HMAC SHA256 hex digest of the raw request body, keyed with your webhook secret. (HTTP header names are case-insensitive; many frameworks lowercase them to x-doola-signature on the way in.)
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, webhookSecret) {
  const expected = crypto
    .createHmac('sha256', webhookSecret)
    .update(rawBody)
    .digest('hex');
  const expectedBuffer = Buffer.from(expected);
  const signatureBuffer = Buffer.from(signature ?? '');
  // timingSafeEqual throws if the buffers differ in length, so reject that first.
  if (expectedBuffer.length !== signatureBuffer.length) {
    return false;
  }
  return crypto.timingSafeEqual(expectedBuffer, signatureBuffer);
}
Always use a constant time comparison (timingSafeEqual or compare_digest). Plain string equality is vulnerable to timing attacks.

Payload

{
  "eventId": "31pLdpvMh4OfO90moxLgLT8AuQr",
  "eventName": "document_aoo_uploaded",
  "eventPayload": {
    "doolaCompanyId": "31pLD0Tq2lm2FsgRBoHv4x3BpzZ",
    "documentId": "31pLdj8SKAU9BYNchcohyto2AxC",
    "documentType": "ArticlesOfOrganization",
    "documentCreatedAt": "2025-08-26 13:49:16.0"
  },
  "timestamp": 1756216157000
}

Events

EventDescription
company_formation_submittedFormation accepted and processing started
company_formation_completedFormation complete, company is active
company_formation_failedFormation failed, check the company’s admin notes
company_filing_date_updatedFiling date was updated by doola
document_aoo_uploadedArticles of Organization ready to download
document_einletter_uploadedEIN Letter ready to download
document_mail_uploadedBusiness mail document uploaded
partner_webhook_disabledYour endpoint was automatically disabled (see below)
You may occasionally receive duplicate document_* events for the same document, for example after doola re-issues a document. Handle uploads idempotently using documentId.

Delivery and retries

If your endpoint does not return a 2xx, doola retries up to 5 times: at 1 minute, 15 minutes, 1 hour, 12 hours, and 24 hours after the previous attempt. Treat every delivery as at least once. After all retries fail, doola automatically disables your endpoint and sends a final partner_webhook_disabled event. Fix your endpoint and re-enable it in the Partner Portal. Re-enabling is a deliberate partner action, so you confirm the endpoint is healthy before traffic resumes. Every delivery attempt (timestamp, event, HTTP status, attempt number) is visible in the Partner Portal.