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

> Creates a custom field on contacts or companies, or updates the one of that name, under the rules of the lemlist app.

# Create or Update Field



## OpenAPI

````yaml post /fields
openapi: 3.0.0
info:
  title: lemlist API
  version: 1.0.0
  description: >-
    Welcome to the lemlist Developer Documentation.


    lemlist is very customizable and open. You'll find on this page all the API
    and integration you can do with lemlist.


    # Rate Limit


    lemlist's API rate limits requests in order to prevent abuse and overload of
    our services.  

    Rate limits are applied on all routes and per API key performing the
    request.  

    The rate limits are **20** requests per **2** seconds.  

    The response provides any information you may need about it:


    | Header | Description |

    | --- | --- |

    | Retry-After | The number of seconds in which you can retry |

    | X-RateLimit-Limit | The maximum requests in that time |

    | X-RateLimit-Remaining | The number of remaining requests you can make |

    | X-RateLimit-Reset | The date when the rate limit will reset |


    _Example of values for the rate limit headers_


    ``` json

    {
        "Retry-After": 2,
        "X-RateLimit-Limit": 20,
        "X-RateLimit-Remaining": 7,
        "X-RateLimit-Reset" : "Tue Feb 16 2021 09:02:42 GMT+0100 (Central European Standard Time)"
    }

     ```

    # Definitions


    ## Team


    A team is the entity of lemlist that can handle users and billing.


    ## Credits


    Credits are the coins a team uses to enrich emails, LinkedIn URLs, etc. via
    the enrich route. Each enrichment feature needs a certain amount of credits
    to run.


    ## User


    You use a user account to connect to lemlist and send messages via the
    connected emails or LinkedIn account.


    ## Campaign


    A campaign is the entity to automate outreach. A campaign has multiple
    sequences composed of steps.


    ## Lead


    A lead is a person that you try to contact via a campaign.


    ## Activity


    An activity is the history of all the steps.


    ## Unsubscribe


    An unsubscribe occurs when a person decides they don't want to receive
    emails from you anymore.


    # Authentication


    All API routes use the dedicated subdomain `api.lemlist.com`.


    lemlist uses API keys to allow access to the API. You can get your lemlist
    API key at our [integration
    page](https://app.lemlist.com/settings/integrations).


    You need to add the `Authorization` header using the `Basic` authentication
    type. `login:password` **where the login is always empty and the password is
    the API key**.


    ⚠️ **Don't forget to add the semicolon (**`:`**) before your API key in curl
    command.**


    > To authorize, use this code: 
      

    ``` shell

    curl https://api.lemlist.com/api/team \
      --user ":YourApiKey"

     ```

    **Make sure to replace** **`YourApiKey`** **with your API key.**


    # Give feedback


    If you want to report a bug, ask for data, or share with us a use case,
    please fill this [form](https://lemlist.typeform.com/to/mfVlkyGf). It will
    help us centralize your needs!
servers:
  - url: https://api.lemlist.com/api
security:
  - basicAuth: []
tags:
  - name: Enrichment Providers
    description: >-
      The data providers lemlist can call to find an email or a phone.


      Internal providers are paid with lemlist credits and always available.
      External providers run on your own account: connect one by saving its API
      key, and it becomes available to your waterfalls. `GET
      /enrichments/providers` is the catalog of provider ids accepted by the
      waterfall endpoints.
  - name: Enrichment Waterfalls
    description: >-
      Control which data providers lemlist calls when enriching a contact, and
      in which order.


      A waterfall is an ordered list of providers for one enrichment `type`
      (`email` or `phone`). Providers are tried one after the other until one
      returns a result.


      Every team has exactly one default waterfall per type (`isDefault: true`).
      While its `editor` is `lemlist` it follows the lemlist behaviour:
      providers you connected with your own API key are tried first, then
      internal providers in a random order. Once a team member edits its
      provider list, `editor` becomes that user's id and the list is followed as
      is; resetting it hands it back to `lemlist`.


      Custom waterfalls (`isDefault: false`) carry `conditions` on the contact
      being enriched, keyed by contact property; every key present must match.
      When a contact is enriched, lemlist runs a single waterfall: the custom
      waterfall of the requested type whose conditions match the contact, or the
      default waterfall when none does. If several match, the one with the most
      condition keys wins, then the most recently updated. Only that waterfall
      runs; when it finds nothing, the enrichment ends without falling back to
      another one.
paths:
  /fields:
    post:
      tags:
        - Fields
      summary: Create or Update Field
      description: >-
        Creates a custom field on contacts or companies, or updates the one the
        entity already has under that `name`, under the rules of the lemlist
        app: the same reserved names, the same type conversions, the same
        permission.


        **Create.** No field of that `name` on the entity: it is created, as the
        **New field** button does in the app. Any API key may create a field.
        The field is created on behalf of the user of the API key and logged in
        the team activity feed. Once created, write it through `POST /contacts`
        or `POST /companies` with its `name` as the key. A new contact field is
        then filled in the background from data lemlist already holds (the
        LinkedIn data of enriched contacts, the lead variable of the same name
        in your campaigns).


        **Update.** A field of that `name` exists: the call updates it, and the
        API key user needs the **Update contact & companies fields** permission,
        as in the app (`403` otherwise, even when nothing would change). What
        can change:


        - `label`, when sent and different;

        - `type`, only to `text` or `multilineText`, from any type but `phone`
        and `user`: the conversions the app offers. The stored values are
        converted, as in the app. Any other `type` than the stored one answers
        `400 TYPE_CHANGE_NOT_ALLOWED`. Note that the app promotes a `text` field
        to `multilineText` on its own when a value with a line break reaches it
        (import, CRM, API), and `GET /fields` then lists it as `multilineText`:
        replaying a body with `type: "text"` converts it back and flattens the
        line breaks, as the app's **Change type** menu does;

        - the options of a `select`, through `upsertOptions` (added when
        missing, never removed), `renameOptions` (the contacts or companies
        holding the old value are rewritten to the new one) and `removeOptions`
        (the contacts or companies holding the option are cleared). Applied in
        that order: renames, removals, additions. A select keeps at least one
        option. Options are matched as in the app, regardless of case and
        surrounding spaces: `gold` matches an existing `Gold`, renaming `Gold`
        to `GOLD` only changes its case, and values are stored without
        surrounding spaces, so a value written on a contact or company matches
        them. An operation already applied reads as done (a rename whose source
        is gone while its target exists, a removal of an absent option).


        Sending the same body again changes nothing and answers `200` with empty
        `changes`.


        Two calls changing the options of the same field at the same time: the
        one planned from a list that changed meanwhile answers `409
        FIELD_CHANGED_RETRY` and writes nothing (the options are written first,
        before any `label` change); read the field again and replay the call.


        **Name.** `name` is the key your integrations write to, and never
        changes afterwards: it must start with a lowercase letter, followed by
        letters and digits only. `label` is optional and defaults to `name` on
        creation.


        **Types.** `select` is created with its `upsertOptions` (at least one).
        A `user` field takes a team member on `POST /contacts` or `POST
        /companies` (email or `usr_` id), as in the app.


        **Read it back.** The response carries the field. A `GET /fields` sent
        right after may take a moment to list it. Renaming or removing an
        option, and converting a type, rewrite every contact or company of the
        team holding a value, within the call.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - entity
                - name
                - type
              properties:
                entity:
                  type: string
                  enum:
                    - contact
                    - company
                  description: Entity the field belongs to.
                name:
                  type: string
                  pattern: ^[a-z][a-zA-Z0-9]*$
                  maxLength: 400
                  description: >-
                    Key to write the field with on `POST /contacts` or `POST
                    /companies`. Starts with a lowercase letter, followed by
                    letters and digits only. Identifies the field to update;
                    never changes afterwards.
                type:
                  type: string
                  enum:
                    - text
                    - multilineText
                    - number
                    - date
                    - select
                    - boolean
                    - phone
                    - user
                    - url
                  description: >-
                    Field data type. On an existing field, only `text` or
                    `multilineText` may differ from the stored type (a
                    conversion), and a `phone` or `user` field keeps its type.
                label:
                  type: string
                  maxLength: 400
                  description: >-
                    Display name of the field, as shown in lemlist. Cannot
                    contain an HTML tag (`<...>`). Optional: defaults to `name`
                    on creation, unchanged when omitted on an update.
                upsertOptions:
                  type: array
                  items:
                    type: string
                  description: >-
                    Select fields only. On creation, the options (at least one).
                    On an update, options to add when missing; the present ones
                    and the others are kept, so the same list replays. Distinct
                    and non-empty; compared as in the app, regardless of case
                    and surrounding spaces (`gold` matches an existing `Gold`),
                    and stored without surrounding spaces.
                renameOptions:
                  type: object
                  additionalProperties:
                    type: string
                  description: >-
                    Select fields only, on an update: `{ "current value": "new
                    value" }`. The option keeps its identity, so the contacts or
                    companies holding the current value are rewritten to the new
                    one.
                removeOptions:
                  type: array
                  items:
                    type: string
                  description: >-
                    Select fields only, on an update: options to drop. The
                    contacts or companies holding one are cleared. At least one
                    option must remain.
            examples:
              create-number:
                summary: create a number field
                value:
                  entity: contact
                  name: annualRevenue
                  label: Annual revenue
                  type: number
              create-select:
                summary: create a select field
                value:
                  entity: contact
                  name: tier
                  label: Tier
                  type: select
                  upsertOptions:
                    - Gold
                    - Silver
                    - Bronze
              update-select-options:
                summary: rename, remove and add options of an existing select
                value:
                  entity: contact
                  name: tier
                  type: select
                  upsertOptions:
                    - Iron
                  renameOptions:
                    Gold: Platinum
                  removeOptions:
                    - Bronze
              convert-to-text:
                summary: convert an existing field to text
                value:
                  entity: contact
                  name: tier
                  type: text
      responses:
        '200':
          description: Field updated (or unchanged, on a replay)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      entity:
                        type: string
                        enum:
                          - contact
                          - company
                        description: Entity the field belongs to
                      name:
                        type: string
                        description: >-
                          Key to write the field with on `POST /contacts` or
                          `POST /companies`
                      label:
                        type: string
                        description: Human-readable display name
                      type:
                        type: string
                        enum:
                          - text
                          - multilineText
                          - number
                          - date
                          - select
                          - boolean
                          - phone
                          - user
                          - url
                        description: Field data type
                      source:
                        type: string
                        enum:
                          - custom
                        description: Always `custom`
                      options:
                        type: array
                        items:
                          type: string
                        description: >-
                          The options of a `select` field, in order (select
                          fields only)
                      created:
                        type: boolean
                        description: '`true` when the call created the field'
                      updated:
                        type: boolean
                        description: >-
                          `true` when the call changed an existing field;
                          `false` on a replay that changed nothing
                      changes:
                        type: array
                        items:
                          type: string
                          enum:
                            - label
                            - type
                            - options
                        description: What the call changed on an existing field
                    required:
                      - entity
                      - name
                      - label
                      - type
                      - source
                      - created
                      - updated
                      - changes
              example:
                success: true
                data:
                  entity: contact
                  name: tier
                  label: Tier
                  type: select
                  source: custom
                  options:
                    - Platinum
                    - Silver
                    - Iron
                  created: false
                  updated: true
                  changes:
                    - options
        '201':
          description: Field created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      entity:
                        type: string
                        enum:
                          - contact
                          - company
                        description: Entity the field belongs to
                      name:
                        type: string
                        description: >-
                          Key to write the field with on `POST /contacts` or
                          `POST /companies`
                      label:
                        type: string
                        description: Human-readable display name
                      type:
                        type: string
                        enum:
                          - text
                          - multilineText
                          - number
                          - date
                          - select
                          - boolean
                          - phone
                          - user
                          - url
                        description: Field data type
                      source:
                        type: string
                        enum:
                          - custom
                        description: Always `custom`
                      options:
                        type: array
                        items:
                          type: string
                        description: >-
                          The options of a `select` field, in order (select
                          fields only)
                      created:
                        type: boolean
                        description: '`true` when the call created the field'
                      updated:
                        type: boolean
                        description: >-
                          `true` when the call changed an existing field;
                          `false` on a replay that changed nothing
                      changes:
                        type: array
                        items:
                          type: string
                          enum:
                            - label
                            - type
                            - options
                        description: What the call changed on an existing field
                    required:
                      - entity
                      - name
                      - label
                      - type
                      - source
                      - created
                      - updated
                      - changes
              example:
                success: true
                data:
                  entity: contact
                  name: annualRevenue
                  label: Annual revenue
                  type: number
                  source: custom
                  created: true
                  updated: false
                  changes: []
        '400':
          description: >-
            The body is refused. `error.code` names the case, `error.message`
            explains it.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: >-
                          Error code: `INVALID_ENTITY_PARAM`,
                          `INVALID_TYPE_PARAM`, `INVALID_LABEL`, `INVALID_NAME`,
                          `OPTIONS_NOT_ALLOWED`, `INVALID_OPTIONS`,
                          `OPTION_NOT_FOUND`, `OPTION_ALREADY_EXISTS`,
                          `FIELD_NAME_RESERVED`,
                          `CONTACT_FIELD_COMPANY_PREFIXED`,
                          `TYPE_CHANGE_NOT_ALLOWED`.
                      message:
                        type: string
              examples:
                invalid-entity-param:
                  summary: '`entity` missing or not contact / company'
                  value:
                    success: false
                    error:
                      code: INVALID_ENTITY_PARAM
                      message: Invalid entity parameter. Must be "contact" or "company"
                invalid-type-param:
                  summary: '`type` missing or unknown'
                  value:
                    success: false
                    error:
                      code: INVALID_TYPE_PARAM
                      message: >-
                        Invalid type parameter. Must be one of: text,
                        multilineText, number, date, select, boolean, phone,
                        user, url
                invalid-label:
                  summary: '`label` empty, too long or holding a tag'
                  value:
                    success: false
                    error:
                      code: INVALID_LABEL
                      message: >-
                        Invalid label. Must be a non-empty string of at most 400
                        characters, without a "<...>" tag
                invalid-name:
                  summary: '`name` missing or off the pattern'
                  value:
                    success: false
                    error:
                      code: INVALID_NAME
                      message: >-
                        Invalid name. Must start with a lowercase letter
                        followed by letters and digits only, at most 400
                        characters
                options-not-allowed:
                  summary: option operations sent for another type than select
                  value:
                    success: false
                    error:
                      code: OPTIONS_NOT_ALLOWED
                      message: >-
                        Option operations (upsertOptions, renameOptions,
                        removeOptions) apply to a select field only
                invalid-options:
                  summary: option operations malformed, or no option left
                  value:
                    success: false
                    error:
                      code: INVALID_OPTIONS
                      message: >-
                        Invalid options. Expected non-empty strings of at most
                        400 characters, without a "<...>" tag, distinct
                        regardless of case and surrounding spaces; a select
                        keeps at least one option
                option-not-found:
                  summary: >-
                    a rename source or a removal names an option the field does
                    not have
                  value:
                    success: false
                    error:
                      code: OPTION_NOT_FOUND
                      message: Option "Bronze" does not exist on this field
                option-already-exists:
                  summary: a rename target is already an option
                  value:
                    success: false
                    error:
                      code: OPTION_ALREADY_EXISTS
                      message: Option "Silver" already exists on this field
                field-name-reserved:
                  summary: name of a default or system field
                  value:
                    success: false
                    error:
                      code: FIELD_NAME_RESERVED
                      message: This name is reserved for a default or system field
                contact-field-company-prefixed:
                  summary: contact field name starting with company
                  value:
                    success: false
                    error:
                      code: CONTACT_FIELD_COMPANY_PREFIXED
                      message: >-
                        A contact field name cannot start with "company": that
                        prefix is reserved for company data on import
                type-change-not-allowed:
                  summary: a conversion the app does not offer
                  value:
                    success: false
                    error:
                      code: TYPE_CHANGE_NOT_ALLOWED
                      message: >-
                        A field can only be converted to text or multilineText,
                        and a phone or user field keeps its type
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: Unauthorized
        '403':
          description: >-
            The API key user lacks the "Update contact & companies fields"
            permission, needed to update or delete a field (creating one needs
            none, as in the app).
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: 'Error code: `FIELD_PERMISSION_DENIED`.'
                      message:
                        type: string
              example:
                success: false
                error:
                  code: FIELD_PERMISSION_DENIED
                  message: >-
                    The API key user is not allowed to update or delete custom
                    fields (permission "Update contact & companies fields")
        '409':
          description: >-
            Another request changed the options of this field between the read
            and the write; nothing was written. Read the field again and replay
            the call.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: 'Error code: `FIELD_CHANGED_RETRY`.'
                      message:
                        type: string
              example:
                success: false
                error:
                  code: FIELD_CHANGED_RETRY
                  message: >-
                    The field options were modified by another request
                    meanwhile: read the field again and replay your call
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

````

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