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

# Create a lead

> Creates a new lead in the practice: a client entity with lead status, lead details, and optionally an initial note in one request.

Requires an API client with **write** access (`canWrite` from `/api/v1/auth/validate`).

**Body fields (common)**

- `entityType` / `entityTypeID`: see `/api/v1/settings/entity-types`. Defaults to Individual when omitted.
- **Naming (depends on entity type):**
  - **Individual / Sole Trader:** `entityName` (required) = given/first name; `entitySurname` = family/last name. Optional `otherName`, `entityInitials`. Names are **not** split automatically — send both fields.
  - **Company and other non-individual types:** `entityName` (required) = full legal or trading name; leave `entitySurname` unset.
- `email`, `mobile`, `telephone`, addresses: optional contact fields.
- `externalSystemID`: your system's identifier for this lead.
- `leadSource`, `leadStatus`, `leadValue`: optional pipeline fields.
  Use **`name`** values from **GET `/api/v1/settings/lead-sources`** and **GET `/api/v1/settings/lead-statuses`**.
- `noteText` / `noteType`: optional initial lead note (`noteType` max 45 characters).

**Example (individual)**

```json
{
  "entityType": "Individual",
  "entityName": "Alex",
  "entitySurname": "Morgan",
  "email": "alex@example.com",
  "leadSource": "Website enquiry",
  "leadStatus": "New"
}
```

**201:** `Location` references the new lead; body includes `entityKey`, `leadDetailID`, and `leadNoteID` when a note was created.

**403:** API client is read-only.

**429:** Rate limit exceeded.

export function DensityStyles() {
  return <style>{`#page-title{font-size:1.5rem!important;line-height:1.25!important;letter-spacing:-.02em;margin-bottom:.4rem!important}#content-area{font-size:.9375rem;line-height:1.55}#content-area p{margin-top:.55em;margin-bottom:.55em}#api-playground-input,#request-example,#response-example{font-size:.8125rem}api-section-heading-title{font-size:1.5rem!important;line-height:1.25!important}api-section-heading{margin-bottom:.5rem}field{padding-top:.35rem;padding-bottom:.35rem;font-size:.875rem}tryit-button{font-size:.8rem}`}</style>;
}

<DensityStyles />


## OpenAPI

````yaml POST /api/v1/leads
openapi: 3.0.4
info:
  title: OnboardMe External API
  description: "Partner integration API for OnboardMe. All routes are under `/api/v1/…` on your **regional** API host.\r\n\r\n---\r\n\r\n## Regional base URLs\r\n\r\nUse the host that matches where the practice is hosted (a practice is tied to one region).\r\n\r\n| Region | Base URL |\r\n| ------ | -------- |\r\n| Australia & New Zealand | `https://anzapi.onboardme.app` |\r\n| United Kingdom | `https://ukapi.onboardme.app` |\r\n| South Africa | `https://zaapi.onboardme.app` |\r\n\r\nIn your HTTP client, pick the matching **Server** / base URL (or set `baseUrl` to one of the URLs above).\r\n\r\nExample: `GET https://ukapi.onboardme.app/api/v1/auth/validate`\r\n\r\n---\r\n\r\n## Authentication\r\n\r\n**Production integrations (recommended):** send both headers on every request:\r\n\r\n- **`X-OM-Auth-ID`** — Client ID (GUID from OnboardMe practice settings)\r\n- **`X-OM-Auth-Key`** — Client secret paired with that Client ID\r\n\r\n**Postman / Swagger Try it out:** use **Authorize** (HTTP Basic) with **Client ID** as the username and **Client secret** as the password. In Postman, set Basic Auth **once on the collection** so every request inherits it — you do not need auth on each request or two separate header fields.\r\n\r\nHTTPS only. Credentials are scoped to one practice; this API does not use end-user passwords.\r\n\r\n---\r\n\r\n## Partner onboarding\r\n\r\n1. Obtain **Client ID** and **secret** from the practice administrator (OnboardMe).\r\n2. Select the **correct regional base URL** (ANZ, UK, or ZA); practices do not span regions.\r\n3. Call `GET /api/v1/auth/validate` to confirm access and read `canWrite` before using any write endpoint.\r\n4. Run an initial **full** import, then use `lastUpdated` on list endpoints for **incremental** sync.\r\n5. On **429 Too Many Requests**, honour `Retry-After` and backoff; avoid polling faster than you need.\r\n\r\n---\r\n\r\n## Pagination and sync\r\n\r\nList endpoints support optional `pageNumber` (1-based, up to 10000) and `lastUpdated` (UTC). Use `lastUpdated` for incremental sync: only rows changed on or after that instant. `lastUpdated` must not be in the future.\r\n\r\n---\r\n\r\n## Rate limits\r\n\r\nPer Client ID (default: 60/minute, 1000/hour, 10000/day). **429** responses include JSON details and headers: `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`.\r\n\r\n---\r\n\r\n## Write access\r\n\r\nCreating or updating data requires `canWrite: true` from `/api/v1/auth/validate`. Read-only clients get **403** on write routes.\r\n\r\nLead endpoints under **`/api/v1/leads`** support listing, detail, notes, create, and **convert-to-client** (promote a lead to an Active client).\r\n\r\n**Contacts** (`/api/v1/contacts/list` and `/api/v1/entities/{entityKey}/contacts`) expose people linked to clients — list, create, and update.\r\n\r\n**ID verifications** — **`POST /api/v1/id-verifications/send`** starts identity verification (optionally with AML via **`includeAml`**). **`POST /api/v1/id-verifications/aml-checks`** runs a standalone **standard** or **extensive** AML screening on an existing client (`entityKey`). Download a verification certificate PDF with **`GET /api/v1/id-verifications/entities/{entityKey}/certificate`**.\r\n\r\n**Onboarding documents** — **`GET /api/v1/onboardings/{key}/documents`** lists requirements per client entity (`isUploaded` / `isBypassed`). Download one file via a short-lived signed S3 URL: **`GET …/entities/{entityOnboardingId}/documents/{documentId}`**. Download all uploaded files as a zip: **`GET …/entities/{entityOnboardingId}/documents/zip`**.\r\n\r\n**Bills** — **`GET /api/v1/bills/list`** lists invoices by **bill date** range (`startDate` / `endDate`). **`GET /api/v1/bills/{billingId}`** returns detail including ledger fields (`externalId`, `externalNumber`, `externalUrl`). **`GET /api/v1/bills/{billingId}/pdf`** downloads the OnboardMe invoice PDF. **`POST /api/v1/bills`** creates an **adhoc** bill for an Active client entity only (no engagement / onboarding entity link; requires `canWrite`; does **not** push to Xero — stores `sendBill` / `syncNow`). When Xero is connected, lines need a revenue account (`extAccountID`) or sale item plus tax (`extTaxID`); use **`GET /api/v1/bills/ledger/status|accounts|tax-rates|branding-themes`**.\r\n\r\n**Proposals** — List a client's proposals with **`GET /api/v1/proposals/list?entityKey=`**. Load previous **services, invoices, recurring billings, and jobs** via **`GET /api/v1/proposals/{key}/pricing`** (or full **`GET /api/v1/proposals/{key}`**). **`POST /api/v1/proposals/{key}/duplicate`** copies pricing, billings, and jobs into a new draft. **`POST /api/v1/proposals/{key}/renew`** does the same and marks the original Renewed (**`GET …/renew-preview`** first for signatory choice). **`POST /api/v1/proposals/from-template`** creates from a saved template. **`POST /api/v1/proposals`** creates an **adhoc** proposal with caller-supplied **services**, optional **XPM jobs**, **FYI jobs**, and **billings**. Catalogs: **`GET /api/v1/proposals/services`**, **`…/xpm-job-templates`**, **`…/xpm-job-categories`**, **`…/xpm-staff`**, **`…/fyi-job-templates`**, **`…/fyi-job-states`**.\r\n\r\n**Recurring billing** — **`GET /api/v1/recurring-billing/list`**, **`GET /api/v1/recurring-billing/{recurringBillingId}`**, and **`GET …/runs`** for schedule list, detail, and generated-run history. Ledger invoice numbers/URLs appear on generated bills, not on the schedule itself.\r\n\r\n---\r\n\r\n## Outbound webhooks\r\n\r\nRegister a subscriber URL with **`POST /api/v1/webhooks`** (requires `canWrite`). Supported event keys are listed at **`GET /api/v1/webhooks/events`** (e.g. `proposal.accepted`, `eform.submitted`). One subscription per event; repeat subscribe with the same URL for multiple events.\r\n\r\n**Subscribe response (`201`):** `{ \"id\", \"webhookSecret\" }` — store `webhookSecret` immediately; it is **not** returned again on list/load.\r\n\r\n**Deliveries:** OnboardMe `POST`s JSON to your URL. Each request includes:\r\n\r\n| Header | Description |\r\n| ------ | ------------- |\r\n| `X-Om-Event` | Event key (e.g. `proposal.accepted`) |\r\n| `X-Om-Event-Id` | Unique idempotency key for this event |\r\n| `X-Om-Timestamp` | Unix time (seconds, UTC) used when signing |\r\n| `X-Om-Signature` | `sha256=<hex>` HMAC (see below) |\r\n\r\n**Signature verification (recommended on your server):**\r\n\r\n1. Read the **raw** request body bytes (do not re-serialize JSON).\r\n2. Build `canonical = {X-Om-Timestamp} + \".\" + {rawBody}`.\r\n3. Compute `expected = \"sha256=\" + HMAC_SHA256_UTF8(webhookSecret, canonical)` (hex **lowercase**).\r\n4. Compare `expected` to `X-Om-Signature` using a constant-time comparison; reject on mismatch.\r\n\r\nThe delivery JSON schema is documented as **`ApiWebhookDeliveryEventDTO`** in Schemas (see **Webhooks** operations). Test deliveries: **`POST /api/v1/webhooks/{id}/test`**.\r\n\r\n---\r\n\r\n## Errors\r\n\r\n- **400** — validation (`message` in body).\r\n- **401** — bad or missing credentials.\r\n- **404** — resource not in the practice (`message`).\r\n\r\nSchemas below include **illustrative** example values; live responses use your data."
  contact:
    name: OnboardMe Support
    email: support@onboardme.app
  version: v1
servers:
  - url: https://anzapi.onboardme.app
    description: Australia & New Zealand — ANZ-hosted practices
  - url: https://ukapi.onboardme.app
    description: United Kingdom — UK-hosted practices
  - url: https://zaapi.onboardme.app
    description: South Africa — ZA-hosted practices
security:
  - ApiClientCredentials: []
paths:
  /api/v1/leads:
    post:
      tags:
        - Leads
      summary: Create a lead
      description: "Creates a new lead in the practice: a client entity with lead status, lead details, and optionally an initial note in one request.\r\n\r\nRequires an API client with **write** access (`canWrite` from `/api/v1/auth/validate`).\r\n\r\n**Body fields (common)**\r\n\r\n- `entityType` / `entityTypeID`: see `/api/v1/settings/entity-types`. Defaults to Individual when omitted.\r\n- **Naming (depends on entity type):**\r\n  - **Individual / Sole Trader:** `entityName` (required) = given/first name; `entitySurname` = family/last name. Optional `otherName`, `entityInitials`. Names are **not** split automatically — send both fields.\r\n  - **Company and other non-individual types:** `entityName` (required) = full legal or trading name; leave `entitySurname` unset.\r\n- `email`, `mobile`, `telephone`, addresses: optional contact fields.\r\n- `externalSystemID`: your system's identifier for this lead.\r\n- `leadSource`, `leadStatus`, `leadValue`: optional pipeline fields.\r\n  Use **`name`** values from **GET `/api/v1/settings/lead-sources`** and **GET `/api/v1/settings/lead-statuses`**.\r\n- `noteText` / `noteType`: optional initial lead note (`noteType` max 45 characters).\r\n\r\n**Example (individual)**\r\n\r\n```json\r\n{\r\n  \"entityType\": \"Individual\",\r\n  \"entityName\": \"Alex\",\r\n  \"entitySurname\": \"Morgan\",\r\n  \"email\": \"alex@example.com\",\r\n  \"leadSource\": \"Website enquiry\",\r\n  \"leadStatus\": \"New\"\r\n}\r\n```\r\n\r\n**201:** `Location` references the new lead; body includes `entityKey`, `leadDetailID`, and `leadNoteID` when a note was created.\r\n\r\n**403:** API client is read-only.\r\n\r\n**429:** Rate limit exceeded."
      requestBody:
        content:
          application/json:
            schema:
              $ref: >-
                #/components/schemas/Application.APIData.DataObjects.LeadCreateRequestDTO
          text/json:
            schema:
              $ref: >-
                #/components/schemas/Application.APIData.DataObjects.LeadCreateRequestDTO
          application/*+json:
            schema:
              $ref: >-
                #/components/schemas/Application.APIData.DataObjects.LeadCreateRequestDTO
      responses:
        '201':
          description: Created
          content:
            text/plain:
              schema:
                $ref: >-
                  #/components/schemas/Application.APIData.DataObjects.LeadCreateResponseDTO
            application/json:
              schema:
                $ref: >-
                  #/components/schemas/Application.APIData.DataObjects.LeadCreateResponseDTO
            text/json:
              schema:
                $ref: >-
                  #/components/schemas/Application.APIData.DataObjects.LeadCreateResponseDTO
        '400':
          description: Bad Request
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            application/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            text/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
        '401':
          description: Unauthorized
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            application/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            text/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
        '403':
          description: Forbidden
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            application/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            text/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
        '429':
          description: Too Many Requests
          content:
            text/plain:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            application/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
            text/json:
              schema:
                $ref: '#/components/schemas/Microsoft.AspNetCore.Mvc.ProblemDetails'
        '500':
          description: Internal Server Error
components:
  schemas:
    Application.APIData.DataObjects.LeadCreateRequestDTO:
      type: object
      properties:
        entityTypeID:
          type: integer
          format: int32
        entityType:
          type: string
          nullable: true
        entityCode:
          type: string
          nullable: true
        externalSystemID:
          type: string
          nullable: true
        entityName:
          type: string
          nullable: true
        otherName:
          type: string
          nullable: true
        entitySurname:
          type: string
          nullable: true
        entityInitials:
          type: string
          nullable: true
        birthDate:
          type: string
          format: date
          nullable: true
        incorporationDate:
          type: string
          format: date
          nullable: true
        birthPlace:
          type: string
          nullable: true
        email:
          type: string
          nullable: true
        telephone:
          type: string
          nullable: true
        mobile:
          type: string
          nullable: true
        taxNumber:
          type: string
          nullable: true
        taxNotRequired:
          type: boolean
        salesTaxNumber:
          type: string
          nullable: true
        regNumber:
          type: string
          nullable: true
        idNumber:
          type: string
          nullable: true
        gender:
          type: string
          nullable: true
        note:
          type: string
          nullable: true
        physicalAddress:
          $ref: >-
            #/components/schemas/Application.APIData.DataObjects.EntityAddressCreateDTO
        postalAddress:
          $ref: >-
            #/components/schemas/Application.APIData.DataObjects.EntityAddressCreateDTO
        leadSource:
          type: string
          nullable: true
        leadStatus:
          type: string
          nullable: true
        leadValue:
          type: number
          format: double
          nullable: true
        noteText:
          type: string
          nullable: true
        noteType:
          type: string
          nullable: true
      additionalProperties: false
      example:
        entityType: Individual
        entityName: Alex
        entitySurname: Morgan
        email: alex@example.com
        mobile: +61 400 555 010
        externalSystemID: CRM-LEAD-9901
        leadSource: Website enquiry
        leadStatus: New
        leadValue: 3200
        noteText: Interested in annual compliance and bookkeeping.
        noteType: API intake
    Application.APIData.DataObjects.LeadCreateResponseDTO:
      type: object
      properties:
        entityKey:
          type: string
          nullable: true
        leadDetailID:
          type: integer
          format: int64
        leadNoteID:
          type: integer
          format: int64
          nullable: true
      additionalProperties: false
      example:
        entityKey: 2c4f6a88-1b3d-5e7f-90ab-cdef12345678
        leadDetailID: 501
        leadNoteID: 8801
    Microsoft.AspNetCore.Mvc.ProblemDetails:
      type: object
      properties:
        type:
          type: string
          nullable: true
        title:
          type: string
          nullable: true
        status:
          type: integer
          format: int32
          nullable: true
        detail:
          type: string
          nullable: true
        instance:
          type: string
          nullable: true
      additionalProperties: {}
    Application.APIData.DataObjects.EntityAddressCreateDTO:
      type: object
      properties:
        address1:
          type: string
          nullable: true
        address2:
          type: string
          nullable: true
        address3:
          type: string
          nullable: true
        address4:
          type: string
          nullable: true
        city:
          type: string
          nullable: true
        state:
          type: string
          nullable: true
        postcode:
          type: string
          nullable: true
        country:
          type: string
          nullable: true
      additionalProperties: false
  securitySchemes:
    ApiClientCredentials:
      type: http
      description: >-
        Swagger / Postman only: **Client ID** as username, **Client secret** as
        password. In Postman, set this once on the **collection** (Authorization
        → Basic Auth) so all requests inherit. For production server-to-server
        code, prefer **`X-OM-Auth-ID`** and **`X-OM-Auth-Key`** headers.
      scheme: basic

````