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

# Create Application

> Create a new application and receive a submission link

Creates a new application and returns a unique link for the primary contact to complete their submission. You don't need to specify a configuration — if `config_id` is omitted, your organization's default configuration is used.

```text theme={null}
POST /api/external/applications
```

## Authentication

Requires an API key with `applications:create` scope.

```bash theme={null}
Authorization: Bearer klara_{client_id}.{secret}
```

## Request body

<ParamField body="primary_contact" type="object" required>
  The main contact who will complete the application.

  <Expandable title="primary_contact properties">
    <ParamField body="email" type="string" required>
      Email address of the primary contact.
    </ParamField>

    <ParamField body="name" type="string">
      Full name of the primary contact.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="country" type="string" required>
  ISO 3166-1 alpha-2 country code (e.g., `GB` for United Kingdom, `IE` for Ireland). Used to select the company registry for validation, so it must be a jurisdiction supported by your configuration.
</ParamField>

<ParamField body="config_id" type="string">
  Application config ID. Must belong to the organization associated with the API key. **If omitted, your organization's default configuration is used.** Only pass this if your organization has multiple configurations and you need a specific one.
</ParamField>

<ParamField body="pre_auth" default="false" type="boolean">
  When `true`, generates a pre-authentication code that allows the participant to bypass email verification. The code expires after 72 hours.
</ParamField>

<ParamField body="company_number" type="string">
  Company registration number. **Required**, unless your configuration has company selection enabled — in that case you can omit it and the applicant picks their company from a registry search when they first open the application.
</ParamField>

<ParamField body="company_name" type="string">
  Name of the company being onboarded. **Required when `company_number` is provided** — it is checked against the registered name in the company registry (see note below).
</ParamField>

<Note>
  **Registry validation:** when `company_number` is provided, it is validated against the company registry before the application is created (Companies House for `GB`, CRO for `IE`). The company must exist, be active, and the provided `company_name` must match the registered name — mismatches return a `400` with a suggestion of the registered name.
</Note>

## Response

Returns `201 Created` on success.

<ResponseField name="application_id" type="string">
  Unique identifier (UUID) for the created application.
</ResponseField>

<ResponseField name="link" type="string">
  URL where the participant should be redirected to complete their application. If your organization has an active [custom domain](/custom-domains), the link uses it (e.g., `https://onboarding.yourcompany.com/apply/...`); otherwise it points at the default Klara host.
</ResponseField>

<ResponseField name="participants" type="array">
  List of participants associated with this application.

  <Expandable title="participant properties">
    <ResponseField name="id" type="string">
      UUID of the participant.
    </ResponseField>

    <ResponseField name="link_slug" type="string">
      Identifier used in the application URL.
    </ResponseField>

    <ResponseField name="email" type="string">
      Email address of the participant.
    </ResponseField>

    <ResponseField name="role" type="string">
      Participant role (`primary`).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pre_auth_code" type="string">
  Pre-authentication code (only present when `pre_auth: true`). Expires 72 hours after creation.
</ResponseField>

<ResponseField name="warning" type="string">
  Warning message (only present if the invite email failed to send). The application is still created successfully — the email can be resent.
</ResponseField>

## Examples

### Basic request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://app.klara-ai.com/api/external/applications \
    -H "Authorization: Bearer klara_abc123def456.your-secret-here" \
    -H "Content-Type: application/json" \
    -d '{
      "config_id": "kyc-standard",
      "primary_contact": {
        "email": "sophie@acme.com",
        "name": "Sophie Mitchell"
      },
      "company_name": "Acme Financial Ltd",
      "company_number": "12345678",
      "country": "GB"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://app.klara-ai.com/api/external/applications', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer klara_abc123def456.your-secret-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      config_id: 'kyc-standard',
      primary_contact: {
        email: 'sophie@acme.com',
        name: 'Sophie Mitchell'
      },
      company_name: 'Acme Financial Ltd',
      company_number: '12345678',
      country: 'GB'
    })
  });

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://app.klara-ai.com/api/external/applications',
      headers={
          'Authorization': 'Bearer klara_abc123def456.your-secret-here',
          'Content-Type': 'application/json'
      },
      json={
          'config_id': 'kyc-standard',
          'primary_contact': {
              'email': 'sophie@acme.com',
              'name': 'Sophie Mitchell'
          },
          'company_name': 'Acme Financial Ltd',
          'company_number': '12345678',
          'country': 'GB'
      }
  )

  data = response.json()
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "application_id": "550e8400-e29b-41d4-a716-446655440000",
  "link": "https://app.klara-ai.com/external/acme-corp/application/ABC123",
  "participants": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "link_slug": "7f3k9m2p4q8r1s5t",
      "email": "sophie@acme.com",
      "role": "primary"
    }
  ]
}
```

### With pre-authentication

Include `pre_auth: true` to generate a code that bypasses email verification:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://app.klara-ai.com/api/external/applications \
    -H "Authorization: Bearer klara_abc123def456.your-secret-here" \
    -H "Content-Type: application/json" \
    -d '{
      "config_id": "kyc-standard",
      "primary_contact": {
        "email": "sophie@acme.com",
        "name": "Sophie Mitchell"
      },
      "company_name": "Acme Financial Ltd",
      "pre_auth": true
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://app.klara-ai.com/api/external/applications', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer klara_abc123def456.your-secret-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      config_id: 'kyc-standard',
      primary_contact: {
        email: 'sophie@acme.com',
        name: 'Sophie Mitchell'
      },
      company_name: 'Acme Financial Ltd',
      pre_auth: true
    })
  });

  const data = await response.json();
  // Redirect user to data.link within 72 hours
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://app.klara-ai.com/api/external/applications',
      headers={
          'Authorization': 'Bearer klara_abc123def456.your-secret-here',
          'Content-Type': 'application/json'
      },
      json={
          'config_id': 'kyc-standard',
          'primary_contact': {
              'email': 'sophie@acme.com',
              'name': 'Sophie Mitchell'
          },
          'company_name': 'Acme Financial Ltd',
          'pre_auth': True
      }
  )

  data = response.json()
  # Redirect user to data['link'] within 72 hours
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "application_id": "550e8400-e29b-41d4-a716-446655440000",
  "link": "https://app.klara-ai.com/external/acme-corp/application/ABC123",
  "participants": [
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "link_slug": "7f3k9m2p4q8r1s5t",
      "email": "sophie@acme.com",
      "role": "primary"
    }
  ],
  "pre_auth_code": "X7K9M2P4Q8R1S5T3"
}
```

<Note>
  When using pre-authentication, redirect the user to the link within the 72-hour window. If the code expires, the user will be prompted to verify their email instead — no error occurs, they just go through the standard verification flow.
</Note>

<Warning>
  To bypass the authentication with the **pre\_auth\_code**, go to an incognito tab so it does redirect you to the dashboard and then add a query param to the **link**  as shown here:`{link}?auth_code={pre_auth_code} `
</Warning>

<Tip>
  Need to re-issue a pre-auth code after it expires or gets consumed? Use the [Refresh Pre-Auth](/api-reference/refresh-pre-auth) endpoint instead of creating a new application.
</Tip>

### With company selection

If your configuration has **company selection** enabled, you don't need to know the applicant's company number — omit `company_number` (and optionally `company_name`) and the applicant picks their company from a registry search when they first open the application. `country` is still required and must be a country your configuration supports.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://app.klara-ai.com/api/external/applications \
    -H "Authorization: Bearer klara_abc123def456.your-secret-here" \
    -H "Content-Type: application/json" \
    -d '{
      "primary_contact": {
        "email": "sophie@acme.com",
        "name": "Sophie Mitchell"
      },
      "country": "GB"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://app.klara-ai.com/api/external/applications', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer klara_abc123def456.your-secret-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      primary_contact: {
        email: 'sophie@acme.com',
        name: 'Sophie Mitchell'
      },
      country: 'GB'
    })
  });

  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://app.klara-ai.com/api/external/applications',
      headers={
          'Authorization': 'Bearer klara_abc123def456.your-secret-here',
          'Content-Type': 'application/json'
      },
      json={
          'primary_contact': {
              'email': 'sophie@acme.com',
              'name': 'Sophie Mitchell'
          },
          'country': 'GB'
      }
  )

  data = response.json()
  ```
</CodeGroup>

<Note>
  Company selection is a configuration-level setting. If it's not enabled for your configuration, omitting `company_number` returns `400 company_number is required`. Contact us to enable it.
</Note>

## Errors

<ResponseExample>
  ```json 400 Bad Request - Missing email theme={null}
  {
    "error": "primary_contact.email is required"
  }
  ```

  ```json 400 Bad Request - Missing company number theme={null}
  {
    "error": "company_number is required"
  }
  ```

  ```json 400 Bad Request - Registry rejection theme={null}
  {
    "error": "The company name and company number you have provided do not match the details in the registry. Did you mean 'ACME FINANCIAL LTD'?"
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error": "Invalid API key"
  }
  ```

  ```json 403 Forbidden theme={null}
  {
    "error": "Config not available for this organization"
  }
  ```

  ```json 503 Service Unavailable - Registry outage theme={null}
  {
    "error": "The company registry (Companies House) is temporarily unavailable. Please try again in a few minutes.",
    "retryable": true
  }
  ```
</ResponseExample>

| Status | Error                                                                    | Cause                                                                                               |
| ------ | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `400`  | `primary_contact.email is required`                                      | The primary contact email is missing                                                                |
| `400`  | `Invalid email address for primary_contact.email`                        | The provided email address is not valid                                                             |
| `400`  | `Invalid config_id`                                                      | The config ID does not exist                                                                        |
| `400`  | `No active configuration found for this organization`                    | `config_id` was omitted and the organization has no configuration to default to                     |
| `400`  | `company_number is required`                                             | `company_number` was omitted and the configuration does not have company selection enabled          |
| `400`  | `country is required for this application configuration`                 | Company selection is enabled but no `country` was provided                                          |
| `400`  | `Country '{country}' is not supported by this application configuration` | The country is not in the configuration's allowed list                                              |
| `400`  | `Company search is not available for country '{country}'`                | Company selection is enabled but no registry supports name search for this country                  |
| `400`  | Registry rejection message                                               | The company was not found, is not active, or the `company_name` doesn't match the registered name   |
| `401`  | `Invalid API key`                                                        | API key is invalid, expired, or inactive                                                            |
| `401`  | `API key missing required scopes: applications:create`                   | API key doesn't have the `applications:create` scope                                                |
| `403`  | `Config not available for this organization`                             | The config belongs to a different organization                                                      |
| `502`  | `Registry validation failed`                                             | The registry lookup failed unexpectedly — safe to retry                                             |
| `503`  | Registry temporarily unavailable                                         | The company registry is down. The response includes `"retryable": true` — retry after a few minutes |
