# Create a customer

Operation ID: `createCustomer`

Group: Accounting › Customers

[Open in the interactive reference](https://docs.api.lensing.ai/lensing/v1/endpoints/createCustomer)

`POST /accounting/customers`

Retry-safe: A write that accepts Idempotency-Key: repeating a request with the same key replays the stored answer instead of executing twice.

Creates a customer. The combination of name, legal entity, and customer type must be unique. If another customer already has the same combination, the request fails with DUPLICATE_CUSTOMER.

The response contains only the new customer's id. Read the record with GET accounting/customers/:id.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Api-Version` | header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version `v1`. |
| `Idempotency-Key` | header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with `400 IDEMPOTENCY_NOT_SUPPORTED` rather than silently ignored. |

## Request body

Required, `application/json`: createCustomerInput.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | The name of the customer, as it appears on invoices. Example: `"Example Robotics Inc"`. |
| `entityId` | string | yes | The legal entity that invoices this customer. To move the customer to another legal entity later, use PATCH accounting/customers/:id. Example: `"3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45"`. |
| `customerType` | string | no | The customer type. Accepted values: 'default', 'partner'. Defaults to 'default'. 'endCustomer' is not supported and fails with END_CUSTOMER_NOT_SUPPORTED. Example: `"default"`. |
| `partnerType` | string | no | The partner type, for a customer whose customerType is 'partner'. Accepted values: 'reseller', 'thirdPartyPayer'. |
| `businessType` | string | no | The business type of the customer. Accepted values: 'company', 'individual'. Defaults to 'company'. Example: `"company"`. |
| `invoiceEmail` | string | no | The email address invoices are sent to. Example: `"billing@example-robotics.com"`. |
| `mainEmail` | string | no | The email address of the customer's main contact. |
| `taxExempt` | boolean | no | Whether the customer is exempt from tax. Defaults to false. |
| `defaultCurrency` | string | no | The default currency for the customer's transactions, as a 3-letter ISO 4217 code. Defaults to the legal entity's currency. Example: `"USD"`. |
| `segment` | string | no | The market segment of the customer. Accepted values: 'SMB', 'MidMarket', 'Enterprise'. Ignored when businessType is 'individual'. |
| `exemptionNumber` | string | no | The tax-exemption certificate number. Accepted only when taxExempt is true. Otherwise the request fails with EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT. |
| `paymentTermCode` | string | no | The code of a payment term on the customer's legal entity's list. A code that is not on the list fails with UNKNOWN_REFERENCE. See code on GET accounting/payment-terms. |
| `parentId` | string | no | The id of the parent customer. An unknown id fails with UNKNOWN_REFERENCE. |
| `partnerId` | string | no | The id of the partner this customer buys through. An unknown id fails with UNKNOWN_REFERENCE. |
| `salesChannel` | string | no | The sales channel for this customer. Accepted values: 'salesAssisted' (sold through a salesperson), 'selfServe'. |
| `additionalContactEmail` | string | no | Another email address for the customer, besides invoiceEmail and mainEmail. |
| `mainContactName` | string | no | The name of the customer's main contact. |
| `preferredLanguage` | string | no | The customer's preferred language. Accepted values: 'english'. |
| `crmCustomerId` | string | no | The customer's identifier in an external CRM system. |
| `businessIdentificationNumber` | string | no | The customer's business registration number. |
| `invoiceConsolidation` | string | no | How the customer's invoices are consolidated. Accepted values: 'customer', 'purchaseOrderNumber', 'salesArrangement'. |
| `invoiceDeliveryMode` | string | no | How invoices are delivered to the customer. Accepted values: 'manual', 'automated'. |
| `isExemptFromCreditCardFee` | boolean | no | Whether the customer is exempt from credit-card fees. Defaults to false. |
| `billableTravelExpenseInvoiceDetail` | string | no | How billable travel and expense items appear on invoices. Accepted values: 'detailed', 'consolidated'. Defaults to 'detailed'. |
| `status` | string | no | The status of the customer. Accepted values: 'active', 'inactive'. Defaults to 'active'. |
| `taxExemptCode` | string | no | The tax-exemption reason code. Cleared when taxExempt is false. |
| `taxRegistrations` | array<object> | no | The customer's tax registrations. |
| `taxRegistrations[].country` | string | yes | The country the registration applies in, as an ISO 3166-1 code. |
| `taxRegistrations[].taxNumber` | string | yes | The tax identification number issued by the tax authority. |
| `taxRegistrations[].type` | string | yes | The kind of tax registration. Accepted values: 'tax', 'salesTax', 'VAT', 'GST', 'EIN', 'TIN'. |
| `taxRegistrations[].effectiveDate` | date | no | The date the registration takes effect. Use format YYYY-MM-DD. |
| `taxRegistrations[].isActive` | boolean | no | Whether the registration is active. Only one active registration is allowed per country and tax type. Defaults to true. |
| `payment` | object | no | The customer's link to a payment provider. `externalPaymentMethodId` requires `externalCustomerId` in the same request. |
| `payment.provider` | string | no | The name of a payment provider connected to your tenant. An unknown name fails with UNKNOWN_PAYMENT_PROVIDER, which lists the connected providers. Required when any other payment field is sent. Example: 'Stripe'. |
| `payment.externalCustomerId` | string | no | The customer's identifier in the payment provider's system. |
| `payment.externalPaymentMethodId` | string | no | The customer's default payment method in the payment provider's system. |
| `addresses` | array<object> | no | The customer's addresses. Mark at most one entry per type as the default with isDefault. When a type has none marked, its first entry is the default. Example: `[{"type":"billTo","line1":"500 Market St","city":"San Francisco","stateProvince":"CA","country":"US","zipCode":"94105","isDefault":true}]`. |
| `addresses[].type` | string | yes | The address type. Accepted values: 'billTo', 'soldTo'. |
| `addresses[].attention` | string | no | The person or department that mail to this address is for. |
| `addresses[].isDefault` | boolean | no | Whether this entry is the default address of its type. |
| `addresses[].line1` | string | yes | The first address line: street number and name, or PO box. |
| `addresses[].line2` | string | no | The second address line: apartment, suite, unit, building, or floor. |
| `addresses[].city` | string | yes | The city or locality. |
| `addresses[].stateProvince` | string | no | The state, province, or region. |
| `addresses[].country` | string | yes | The country, as a name or ISO 3166-1 code. |
| `addresses[].zipCode` | string | yes | The postal or ZIP code. |
| `externalIdentifiers` | array<object> | no | The customer's identifiers in other systems, one per configured field name. A field name not configured for your tenant fails with UNKNOWN_EXTERNAL_IDENTIFIER. |
| `externalIdentifiers[].fieldName` | string | yes | The configured field name of the identifier. Example: 'netsuiteCustomerId'. |
| `externalIdentifiers[].value` | string | yes | The identifier in the other system. |
| `externalIdentifiers[].externalUrl` | string | no | A link to the record in the other system. |

```json
{
  "name": "Example Robotics Inc",
  "entityId": "3b7d5e9c-1a24-4f80-9c6d-2e8f70b13a45",
  "customerType": "default",
  "partnerType": "<partnerType>",
  "businessType": "company",
  "invoiceEmail": "billing@example-robotics.com",
  "mainEmail": "<mainEmail>",
  "taxExempt": true,
  "defaultCurrency": "USD",
  "segment": "<segment>",
  "exemptionNumber": "<exemptionNumber>",
  "paymentTermCode": "<paymentTermCode>",
  "parentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "partnerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "salesChannel": "<salesChannel>",
  "additionalContactEmail": "<additionalContactEmail>",
  "mainContactName": "<mainContactName>",
  "preferredLanguage": "<preferredLanguage>",
  "crmCustomerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "businessIdentificationNumber": "<businessIdentificationNumber>",
  "invoiceConsolidation": "<invoiceConsolidation>",
  "invoiceDeliveryMode": "<invoiceDeliveryMode>",
  "isExemptFromCreditCardFee": true,
  "billableTravelExpenseInvoiceDetail": "<billableTravelExpenseInvoiceDetail>",
  "status": "<status>",
  "taxExemptCode": "<taxExemptCode>",
  "taxRegistrations": [
    {
      "country": "<country>",
      "taxNumber": "<taxNumber>",
      "type": "<type>",
      "effectiveDate": "2026-01-15",
      "isActive": true
    }
  ],
  "payment": {
    "provider": "<provider>",
    "externalCustomerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "externalPaymentMethodId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  "addresses": [
    {
      "type": "billTo",
      "line1": "500 Market St",
      "city": "San Francisco",
      "stateProvince": "CA",
      "country": "US",
      "zipCode": "94105",
      "isDefault": true
    }
  ],
  "externalIdentifiers": [
    {
      "fieldName": "<fieldName>",
      "value": "<value>",
      "externalUrl": "<externalUrl>"
    }
  ]
}
```

## Response

`200` Success

Under `data` (createCustomerOutput):

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | The unique identifier for the created customer. Example: `"9f2c6a10-7d34-4c8e-9b21-5a0f3e6d81b7"`. |

```json
{
  "data": {
    "id": "9f2c6a10-7d34-4c8e-9b21-5a0f3e6d81b7"
  },
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}
```

## Response headers

- `Idempotency-Replayed` — Present and `true` only when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent as `false`.

## Errors

| Code | Status |
| --- | --- |
| `INVALID_ENTITY` | 400 |
| `INVALID_FIELD_VALUE` | 400 |
| `MULTIPLE_DEFAULT_ADDRESSES` | 400 |
| `DUPLICATE_CUSTOMER` | 400 |
| `END_CUSTOMER_NOT_SUPPORTED` | 400 |
| `UNKNOWN_EXTERNAL_IDENTIFIER` | 400 |
| `DUPLICATE_EXTERNAL_IDENTIFIER` | 400 |
| `UNKNOWN_REFERENCE` | 400 |
| `UNKNOWN_PAYMENT_PROVIDER` | 400 |
| `PAYMENT_METHOD_REQUIRES_CUSTOMER_ID` | 400 |
| `EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT` | 400 |
| `IDEMPOTENCY_KEY_CONFLICT` | 409 |
| `IDEMPOTENCY_PAYLOAD_MISMATCH` | 422 |

## Statuses

- `400` — Invalid request or business failure. Codes: INVALID_ENTITY, INVALID_FIELD_VALUE, MULTIPLE_DEFAULT_ADDRESSES, DUPLICATE_CUSTOMER, END_CUSTOMER_NOT_SUPPORTED, UNKNOWN_EXTERNAL_IDENTIFIER, DUPLICATE_EXTERNAL_IDENTIFIER, UNKNOWN_REFERENCE, UNKNOWN_PAYMENT_PROVIDER, PAYMENT_METHOD_REQUIRES_CUSTOMER_ID, EXEMPTION_NUMBER_REQUIRES_TAX_EXEMPT
- `401` — The request carries no valid access token.
- `403` — Not authorized
- `404` — Not found
- `409` — The Idempotency-Key is still being processed by another request.
- `422` — The Idempotency-Key was already used with a different request payload.
- `429` — Too many requests from this client address. The response has no body and no `Retry-After` header.
- `500` — Internal server error
