> ## Documentation Index
> Fetch the complete documentation index at: https://docs.doola.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Authenticate with the raw API key in the Authorization header. Never add a Bearer prefix.
> Use the sandbox base URL https://api.test.doola.com and a dk_test_ key in examples unless the user asks for production.
> Send an Idempotency-Key header on POST /v1/partner/customers and POST /v1/partner/companies. No other endpoint takes one.
> Every response is wrapped as {payload, error}. Read fields from payload and branch on error.code, never on the message.
> Drive formation progress from webhooks plus a reconciliation sweep, never a polling loop.
> Embedded SDK (@doola/js): the dk_ key stays on the server and mints customer sessions; the browser gets only a pk_ key and the session. onFormed carries only companyId and can fire more than once. Before charging, read the company with the dk_ key, require formationSubmissionStatus AWAITING_PAYMENT, check the owner's email, and price on the server. Then POST payment-confirmed, which answers 200 with an empty body, and replace the SDK element with a new doola.create() (never append a second one).
> The doola Formation MCP server at https://mcp.doola.com is for founders forming their own company with their own doola account. Partners integrate the Partner API or the Embedded SDK. The /mcp endpoint on this docs site only searches these docs.
> For a full capability summary with the rules above, read https://docs.doola.com/skill.md.

# Server reference

> @doola/js/server helpers, and the Partner API endpoints an SDK integration uses.

## @doola/js/server

```ts theme={null}
import { createSessionHandler, createCustomerSession } from '@doola/js/server';
```

Runs on Node 18 or later, or any runtime with the web-standard `fetch`, `Request` and `Response`. Both helpers send your key as the raw `Authorization` header, pick `api.doola.com` or `api.test.doola.com` from its prefix, and time out after 10 seconds.

### createSessionHandler(options)

```ts theme={null}
function createSessionHandler(options: {
  apiKey: string | undefined;
  getCustomer: (request: Request) => DoolaCustomer | null | Promise<DoolaCustomer | null>;
  onFailure?: (failure: CustomerSessionFailure) => void | Promise<void>;
}): (request: Request) => Promise<Response>;
```

Builds a complete session route.

* **`apiKey`:** your `dk_` secret key. A key that is set but invalid, including a `pk_` key, throws when you create the handler. A missing key is refused on each request instead, so builds without the secret still pass.
* **`getCustomer`:** return the signed-in customer, or `null` when nobody is signed in. `null` answers 401.
* **`onFailure`:** called with the reason whenever doola does not return a session. Your own 401 for a signed-out user does not call it.

Every response carries `Cache-Control: no-store`. A success answers 200 with `{ accessToken, expiresIn }`.

### createCustomerSession(options)

```ts theme={null}
function createCustomerSession(options: {
  apiKey: string | undefined;
  customer: DoolaCustomer;
}): Promise<{
  status: number;
  body: { accessToken: string; expiresIn: number } | null;
  code?: string;
  failure?: CustomerSessionFailure;
}>;
```

Creates one session and returns what your route should answer, for frameworks that do not use `Request` and `Response`: `status`, with `body` as JSON, or `{ code }` as JSON when `code` is set (a 409). It rejects only when the key is missing or invalid.

### DoolaCustomer

| Field | Type | Notes |
| - | - | - |
| `email` | `string` | Required |
| `externalCustomerId` | `string` | Your user id, up to 255 characters. Matched before `email` |
| `firstName`, `lastName` | `string` | Used only when doola creates the customer |
| `countryOfResidence` | `string` | ISO 3166-1 alpha-3. Used only when doola creates the customer |
| `phoneNumber` | `string` | E.164. Used only when doola creates the customer |

Only these fields are sent to doola, whatever else the object carries.

### How doola's answers map

| doola answered | Your route answers | `failure.reason` |
| - | - | - |
| A session | 200 with `{ accessToken, expiresIn }` | |
| 401 | 502 | `doola_unauthorized` |
| 409 | 409 with `{ code }`, doola's error code, or no body when doola sent none | `doola_error` |
| Any other error | The same status, no body | `doola_error` |
| Nothing, or a timeout | 502 | `doola_unreachable` |
| A 2xx without a usable session | 502 | `invalid_response` |

`failure` also carries `doolaStatus` and `doolaCode`, doola's `error.code`, when there was one.

## Partner API endpoints

An SDK integration uses five Partner API endpoints, all with your `dk_` secret key:

| Endpoint | Use it to |
| - | - |
| [`POST /v1/partner/customer-sessions`](/api/api-reference/customer-sessions/create-a-customer-session) | Create a session for the signed-in customer. See [Create sessions](/sdk/sessions) |
| [`GET /v1/partner/companies/{companyId}`](/api/api-reference/companies/get-a-company) | Check the company's status before you charge |
| [`GET /v1/partner/customers/{customerId}`](/api/api-reference/customers/get-a-customer) | Check the company belongs to the signed-in customer |
| [`GET /v1/partner/references/state-fees`](/api/api-reference/reference-data/list-state-filing-fees) | Price the state filing fee |
| [`POST /v1/partner/companies/{companyId}/payment-confirmed`](/api/api-reference/companies/confirm-payment-for-a-draft-formation) | Start the formation once you are paid. See [Take payment](/sdk/payments#confirm-payment-responses) |

One more is optional:

| Endpoint | Use it to |
| - | - |
| [`GET /v1/partner/sdk/keys`](/api/api-reference/sdk/get-your-publishable-key) | Read your publishable key from your server instead of copying it from the Partner Portal. It returns `{ publishableKey, createdAt }` and creates the key the first time you ask |

Everything after payment, from webhooks to documents and required actions, uses the rest of the [Partner API](/api/introduction).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.