Keys and environment
- Your page uses your
pk_live_publishable key, and your server uses yourdk_live_secret key. They come as a pair. - The secret key is in your server’s environment only. Search your built frontend for
dk_live_, and expect nothing. - Branding is set in your production Partner Portal account. Sandbox and production are separate accounts.
- Your CSP allows
script-src https://js.doola.comandframe-src https://sdk.doola.com, and thedoola-jsTrusted Types policy if you enforce Trusted Types.
Sessions
- The session route reads the customer from your own sign-in, never from the request body.
- It answers 401 only when nobody is signed in, and turns doola’s 401 into a 502.
@doola/js/serverdoes both. - It accepts
POSTonly, applies your CSRF protection, and sendsCache-Control: no-store. - It sends
externalCustomerId, so a customer who changes their email with you stays the same customer. - It answers doola’s 409 with
{ code }, andfetchAccessTokenrejects with thatcode.@doola/js/serverdoes the first. - You log the doola error code from failed sessions on your server.
Payment
-
onFormedopens your checkout, and opening it twice for the same company creates one order. - Before charging, your server checks that the company belongs to the signed-in customer and is still
AWAITING_PAYMENT.CANCELLED,FAILEDand unknown statuses are refused, never shown as paid. - Your server prices the formation. Nothing about the price comes from the browser.
- You keep one order per
companyId, and each charge attempt has its own idempotency key, so a retry after a declined card still goes through. - You confirm payment only after the charge succeeds, and retry the confirmation on a network error or a 5xx.
-
409 E_COMPANY_CANCELLEDrefunds the founder. - After confirming, you replace the SDK element with a new
doola.create(), so the founder sees their company and the old payment screen is gone. - A scheduled sweep confirms charged orders that were never confirmed.
After payment
- Your production webhook URL and signing secret are set in the Partner Portal, and your endpoint verifies signatures.
- You handle
company_formation_submitted,company_formation_completed,company_formation_failedandcompany_ein_issued. - You bring the founder back to the SDK on
signature_ss4_reminder_dueandsignature_form8821_reminder_due. - You handle
company_name_options_required. The founder can send new names in the SDK, and your answer through the Required actions API replaces theirs. - doola has every domain that hosts the SDK, so signing renders inside it.
On the page
- Your page shows its own fallback when
loadDoola()rejects, and whenonLoadErrorreportsrender_error. -
partner_session_expiredsends the user to your sign-in. -
email_in_usegives the founder a way forward, such as a different email or your support. -
external_id_conflictalerts your team, since only a fix to your user id mapping resolves it, andcustomer_revokedoffers your support. - You log
mint_failedand alert when your session route keeps failing. The iframe offers the founder Try again itself. - You call
doola.destroy()when your user signs out, and never on an ordinary route change. - You keep one SDK instance per page, so callbacks reach the screen that is mounted now.
- You tested on Chrome, Firefox, Safari and iOS Safari, and on a phone-sized screen.
In production
- You never create test formations with live keys. Every confirmed live formation is filed with the state.
- Your team knows how to reach doola to cancel an unpaid formation.