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

# Create custom field

> Creates a custom field on your team's people. The key is derived from the label. Creating the same label with the same type again returns the existing field with `already_existed` set to `true`.

<Note>
  **Required scope:** `CRM_WRITE`
</Note>

## Body fields

| Field | Type | Required | Description |
| - | - | - | - |
| `label` | string | yes | Display name, 1 to 255 characters, with at least one letter or digit |
| `type` | string | yes | `TEXT`, `NUMBER`, `DATE` or `BOOLEAN` |

`DROPDOWN` fields are synced from your CRM integrations and cannot be created here.

## Key derivation

The `key` is derived from the label: lowercase, accents removed, runs of non-alphanumeric characters replaced by `_`, truncated to 64 characters. `Lead Source` becomes `lead_source`.

A label that resolves to a built-in field key is rejected with `ATTRIBUTE_KEY_RESERVED`. The reserved keys are `name`, `phone_numbers`, `company`, `job_title`, `emails`, `last_activity`, `website`, `created_at` and `updated_at`.

## Creating the same field twice

The call is safe to repeat. If a field with the same key and type already exists, the endpoint returns `201` with `already_existed` set to `true` and the label it was first created with. Nothing is created.

```json theme={null}
{
  "data": {
    "key": "lead_source",
    "label": "Lead Source",
    "type": "TEXT",
    "already_existed": true
  }
}
```

If the key exists with a different type, the request returns `409 ATTRIBUTE_KEY_CONFLICT`.

## Limits

A team can hold up to 150 `TEXT`, 50 `NUMBER`, 30 `DATE` and 30 `BOOLEAN` custom fields. Once a type is full, creating another field of that type returns `409 ATTRIBUTE_SLOTS_EXHAUSTED`.

## Errors

| Status | Code | When |
| - | - | - |
| `400` | `ATTRIBUTE_LABEL_INVALID` | `label` is blank, longer than 255 characters, or has no letter or digit |
| `400` | `ATTRIBUTE_KEY_RESERVED` | The label resolves to a built-in field key |
| `400` | `INVALID_REQUEST_BODY` | `type` is missing or is not one of `TEXT`, `NUMBER`, `DATE`, `BOOLEAN` |
| `403` | `API_KEY_INSUFFICIENT_SCOPE` | The key does not hold `CRM_WRITE` |
| `404` | `TEAM_NOT_FOUND` | The workspace is not on the new contact model |
| `409` | `ATTRIBUTE_KEY_CONFLICT` | A field with this key already exists with another type |
| `409` | `ATTRIBUTE_SLOTS_EXHAUSTED` | No free slot is left for this type |


## OpenAPI

````yaml POST /v2/api/crm/attributes
openapi: 3.0.3
info:
  title: Allo API
  description: >-
    Allo API provides programmatic access to your Allo account, allowing you to
    manage webhooks, retrieve calls and contacts, and send SMS messages.


    All requests to `/v1/api/**` endpoints automatically go through quota
    checking and scope validation.
  version: 1.0.0
  contact:
    name: Allo Support
servers:
  - url: https://api.withallo.com
    description: Production server
security: []
tags:
  - name: Summary Templates
    description: >-
      Manage call summary templates that control how AI-generated call summaries
      are structured for your team.
  - name: Webhooks
    description: >-
      Manage webhook endpoints to receive real-time notifications about events
      in your Allo account. Each endpoint subscribes to one or more event topics
      and is verified with a signing secret.
  - name: Calls
    description: >-
      Retrieve and search call records with filtering and pagination. Filter
      calls by your Allo phone number.
  - name: Contacts
    description: >-
      Search and retrieve contact information with sorting and pagination.
      Includes engagement level tracking.
  - name: SMS
    description: Send SMS messages to phone numbers using your Allo numbers.
  - name: Phone Numbers
    description: Retrieve information about your Allo phone numbers.
  - name: Analytics
    description: Pre-computed call metrics, team performance, and outbound dial funnel
  - name: CRM
    description: Manage people, companies, and deals in your CRM.
  - name: Notes
    description: >-
      Internal team notes on conversations and CRM people, with @mention
      support. Notes are never visible to the contact.
  - name: Threads
    description: >-
      Team discussion threads attached to a conversation item (call, SMS, or
      conversation note). One thread per item.
  - name: AI Receptionist
    description: >-
      Read and write the AI receptionist configuration of a phone line: business
      details, voice, prompt, capabilities, business hours, transfer rules,
      scheduling calendars and knowledge sources.
paths:
  /v2/api/crm/attributes:
    post:
      tags:
        - CRM
      summary: Create custom contact field
      description: >-
        Creates a custom field on your team's people. The key is derived from
        the label. Creating the same label with the same type again returns the
        existing field with `already_existed` set to `true`.
      operationId: createCrmAttribute
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCrmAttributeRequest'
            example:
              label: Lead Source
              type: TEXT
      responses:
        '201':
          description: The custom field that was created, or the existing one
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/CreateCrmAttributeResult'
              example:
                data:
                  key: lead_source
                  label: Lead Source
                  type: TEXT
                  already_existed: false
        '400':
          $ref: '#/components/responses/ApiValidationError'
        '401':
          $ref: '#/components/responses/ApiUnauthorized'
        '403':
          $ref: '#/components/responses/ApiForbidden'
        '404':
          $ref: '#/components/responses/ApiNotFound'
        '409':
          $ref: '#/components/responses/ApiConflict'
        '429':
          $ref: '#/components/responses/ApiRateLimited'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    CreateCrmAttributeRequest:
      type: object
      description: Request body for creating a custom contact field
      required:
        - label
        - type
      properties:
        label:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Display name of the field. The key is derived from it: lowercase,
            accents removed, runs of non-alphanumeric characters replaced by
            `_`, truncated to 64 characters. Must contain at least one letter or
            digit and must not resolve to a built-in field key such as `name`,
            `company` or `website`.
          example: Lead Source
        type:
          type: string
          enum:
            - TEXT
            - NUMBER
            - DATE
            - BOOLEAN
          description: Value type of the field
          example: TEXT
    CreateCrmAttributeResult:
      type: object
      properties:
        key:
          type: string
          description: Key derived from the label
          example: lead_source
        label:
          type: string
          description: >-
            Stored label. When the field already existed, this is the label it
            was first created with.
          example: Lead Source
        type:
          type: string
          enum:
            - TEXT
            - NUMBER
            - DATE
            - BOOLEAN
          example: TEXT
        already_existed:
          type: boolean
          description: >-
            `true` when a field with the same key and type already existed and
            nothing was created
          example: false
    ApiError:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              type: string
            code:
              type: string
            message:
              type: string
            retryable:
              type: boolean
            request_id:
              type: string
            retry_after_seconds:
              type: integer
              nullable: true
  responses:
    ApiValidationError:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ApiUnauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ApiForbidden:
      description: API key lacks the required scope or access to the resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ApiNotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ApiConflict:
      description: Conflict with existing resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
    ApiRateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiError'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization

````

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