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

# endstate.units.create

> Creates an item. Pass an idempotencyKey you control - the item's own external_id works well - so a retry from a later run recovers this same item rather than creating a second one. Without one core generates a key, which only dedupes retries within this call.

```ts theme={null}
create(body: CreateUnitRequest, options?: IdempotentRequestOptions): Promise<Unit>
```

|                 |                                                        |
| --------------- | ------------------------------------------------------ |
| Endpoint        | [`POST /v1/units`](/api-reference/units/create-a-unit) |
| Credential      | Secret key (`end_sk_...`)                              |
| Retry class     | `keyed`                                                |
| Idempotency key | Accepted                                               |

Carries an idempotency key. Retried on network failure, timeout, `429`, and `409 idempotency.in_progress` - never on a `5xx`.

## Example

```ts theme={null}
const result = await endstate.units.create({
  collection_id: "8e1a7f50-90ab-4cde-8012-3456789abcde",
});
```

## Parameters

<ParamField body="external_id" type="string">
  Unique identifier for the unit within your organization.
</ParamField>

<ParamField body="name" type="string">
  Human-readable name for the unit.
</ParamField>

<ParamField body="attributes" type="object">
  Free-form JSON attributes for the unit.
</ParamField>

<ParamField body="collection_id" type="string" required>
  Collection this unit belongs to.
</ParamField>

<ParamField body="redirect_url" type="string | null">
  Tap redirect URL for this unit. Omit or null for none.
</ParamField>

## Returns

`201` - `Unit`.

<ResponseField name="id" type="string" required />

<ResponseField name="external_id" type="string | null" required />

<ResponseField name="name" type="string | null" required />

<ResponseField name="attributes" type="object | null" required />

<ResponseField name="created_at" type="string" required />

<ResponseField name="redirect_url" type="string | null" required>
  Tap redirect URL for this unit; takes precedence over product/collection/org defaults.
</ResponseField>

<ResponseField name="collection" type="object | null" required>
  The unit's collection. Null only for units created before collections existed.
</ResponseField>

<ResponseField name="chips" type="object[]" required>
  Chips paired to this unit.
</ResponseField>

## Errors

Branch on `error.code`, never on the HTTP status - several codes share one.

| Code                       | HTTP | Retry         |
| -------------------------- | ---- | ------------- |
| `auth.unauthorized`        | 401  | Do not retry  |
| `collection.not_found`     | 404  | Do not retry  |
| `idempotency.in_progress`  | 409  | Safe to retry |
| `idempotency.key_conflict` | 409  | Do not retry  |
| `internal.error`           | 500  | Safe to retry |
| `unit.already_exists`      | 409  | Do not retry  |
| `validation.failed`        | 400  | Do not retry  |

See [Errors and retries](/sdks/core/errors-and-retries) for the error types and how to narrow them.
