> ## 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.

> Adds a branch to a condition step and returns it.

# Add Condition Branch

<Note>
  New to condition branches? Start with
  [List Condition Branches](/api-reference/endpoints/sequences/list-condition-branches), which explains
  how a step branches and how a branch is addressed.
</Note>

The new branch is inserted **just before the Else branch**, so it becomes the lowest-priority branch
of the step. Reorder afterwards with
[`PATCH …/branches`](/api-reference/endpoints/sequences/reorder-condition-branches) if it should be
tested earlier.

lemlist mints the empty sub-sequence the branch routes to and returns its id as `sequenceId`. Pass
that id to [`POST /sequences/{sequenceId}/steps`](/api-reference/endpoints/sequences/add-step-to-sequence)
to fill the branch with steps.

## A branch carries the value it tests

There are no blank branches: the body must say what this one matches, and a step's condition is never
sent here. `conditionKey` in the body is refused with `SEQUENCE_BRANCH_CONDITION_KEY_NOT_ALLOWED` —
every branch of a step shares the step's condition.

Only four conditions host more than one branch:

| Condition         | Required in the body                                                                                                                                              |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `customLeadInfo`  | `customValue` — unless `customOperator` is `empty` or `notEmpty`, which refuse one. The tested **field** is inherited from the step, so `customField` is optional |
| `hasScore`        | nothing — the branch inherits a complete `>= 80` band. Send `scoreComparator` and `scoreThreshold` to give it its own                                             |
| `hasEmailAddress` | `emailStatusFilter`                                                                                                                                               |
| `aircallDone`     | `callStatusFilter`                                                                                                                                                |

Any other condition answers `400`: `not-multi-capable` when the condition supports a single branch
plus Else, `SEQUENCE_BRANCH_CONDITION_NOT_CONFIGURABLE` when it has no branch parameters on the API.

<Note>
  On a `customLeadInfo` step every branch tests the **same field** — only the operator and the value
  differ. Sending a `customField` that differs from the step's changes it on every branch at once.
</Note>

## When the campaign is running

Adding a branch changes the shape of the tree leads walk, so it is refused with `409` once leads have
entered the campaign — see
[Editing a running campaign](/api-reference/endpoints/sequences/list-condition-branches#editing-a-running-campaign).


## OpenAPI

````yaml post /sequences/{sequenceId}/steps/{stepId}/branches
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: []
paths:
  /sequences/{sequenceId}/steps/{stepId}/branches:
    parameters:
      - name: sequenceId
        in: path
        required: true
        description: The unique identifier of the sequence holding the condition step
        example: seq_lkCSKd32qSZZTe5Ru
        schema:
          type: string
      - name: stepId
        in: path
        required: true
        description: >-
          The unique identifier of the condition step, from `GET
          /campaigns/{campaignId}/sequences`
        example: stp_Ae93hiemDkypHLys2
        schema:
          type: string
    post:
      tags:
        - Sequences
      summary: Add Condition Branch
      description: >-
        Adds a branch to a condition step, just before the Else branch, and
        mints the empty sub-sequence it routes to. Add steps to that branch by
        calling `POST /sequences/{sequenceId}/steps` with the returned
        `sequenceId`.


        A branch carries the value it tests from the moment it is created -
        there are no blank branches - so the body must say what this one
        matches. The step's condition is shared by every branch and is never
        sent here: `conditionKey` in the body is refused.


        Only four conditions host several branches: `customLeadInfo`,
        `hasScore`, `hasEmailAddress` and `aircallDone`. Each needs its own
        tested value in the body, except `hasScore`, whose new branch inherits a
        complete `>= 80` band and can be added from an empty body.
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: >-
                    The branch's display name. An empty string clears it, and
                    lemlist falls back to labelling the branch "Branch 1",
                    "Branch 2", … by rank. The Else branch cannot be named.
                delayType:
                  type: string
                  enum:
                    - within
                    - waitUntil
                  description: >-
                    How a lead-action condition waits: `within` branches once
                    the `delay` window is over, `waitUntil` parks the lead until
                    the action happens, with no time bound. Ignored by the
                    conditions that store no time window (`customLeadInfo`,
                    `hasEmailAddress`).
                delay:
                  type: integer
                  description: Length of that time window, in days.
                scoreComparator:
                  type: string
                  enum:
                    - $gte
                    - $lt
                  description: >-
                    `hasScore` only - how the lead's score is compared to
                    `scoreThreshold`.
                scoreThreshold:
                  type: integer
                  minimum: 0
                  maximum: 100
                  description: '`hasScore` only - the score this branch tests against.'
                emailStatusFilter:
                  type: array
                  minItems: 1
                  items:
                    type: string
                    enum:
                      - deliverable
                      - risky
                      - undeliverable
                      - unverified
                  description: >-
                    `hasEmailAddress` only - the email statuses this branch
                    matches. Required to add a branch on that condition.
                callStatusFilter:
                  type: array
                  minItems: 1
                  items:
                    type: string
                  description: >-
                    `aircallDone` only - the call-status keys this branch
                    matches. The keys are the team's own (defaults plus custom
                    dispositions), so any non-empty string is accepted. Required
                    to add a branch on that condition.
                customField:
                  type: string
                  description: >-
                    `customLeadInfo` only - the field to test. A bare name reads
                    as a lead variable (`jobTitle` becomes
                    `variables.jobTitle`); prefix with `fields.` to test a
                    contact field. Every branch of a step tests the same field,
                    so changing it here changes it on all of them.
                customOperator:
                  type: string
                  enum:
                    - equal
                    - contains
                    - empty
                    - notEmpty
                  description: >-
                    `customLeadInfo` only - how the field is compared. `equal`
                    and `contains` need a `customValue`; `empty` and `notEmpty`
                    refuse one.
                customValue:
                  type: string
                  description: >-
                    `customLeadInfo` only - the value the field is compared to.
                    Required for `equal` and `contains`, and refused for `empty`
                    and `notEmpty`.
            examples:
              Custom lead variable:
                value:
                  name: Marketing
                  customField: jobTitle
                  customOperator: contains
                  customValue: CMO
              Email status:
                value:
                  name: Risky addresses
                  emailStatusFilter:
                    - risky
                    - unverified
              Lead score:
                value:
                  name: Cold leads
                  scoreComparator: $lt
                  scoreThreshold: 40
      responses:
        '201':
          description: The branch was added.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConditionBranch'
              example:
                sequenceId: seq_Nb4vKq7Xm2Rd9Tz1L
                index: 2
                key: customLeadInfo
                name: Marketing
                customField: variables.jobTitle
                customOperator: contains
                customValues:
                  - CMO
        '400':
          description: >-
            The body or the step cannot host the branch.
            `SEQUENCE_BRANCH_VALUE_REQUIRED` - the condition needs a tested
            value the body did not carry.
            `SEQUENCE_BRANCH_CONDITION_NOT_CONFIGURABLE` - the condition has no
            branch parameters on the API.
            `SEQUENCE_BRANCH_CONDITION_KEY_NOT_ALLOWED` - `conditionKey` was
            sent. `not-multi-capable` - the condition supports a single branch
            plus Else. `cap-reached` - the step is at its 200-entry ceiling.
            `SEQUENCE_BRANCH_INVALID_PARAM` - a malformed body or path
            identifier. A bad `customField`, `customOperator` or `customValue`
            answers with a plain message and no `code` - for instance
            `customValue is required for operator "contains"`.
          content:
            application/json:
              example:
                error: >-
                  emailStatusFilter is required to add a branch on condition
                  "hasEmailAddress"
                code: SEQUENCE_BRANCH_VALUE_REQUIRED
        '401':
          description: Unauthorized - invalid or missing API key
          content:
            text/plain:
              example: The authentication you supplied is incorrect
        '402':
          description: >-
            The team's plan is below the Email Pro floor every sequence route
            sits on.
          content:
            text/plain:
              example: route is available starting emailPro plan
        '403':
          description: >-
            `SEQUENCE_BRANCH_BETA_REQUIRED` - branch writes are in closed beta
            and answer `403` unless the beta is enabled for your team. Reading
            branches is not gated.
          content:
            application/json:
              example:
                error: Condition branches are not enabled for this team
                code: SEQUENCE_BRANCH_BETA_REQUIRED
        '404':
          description: >-
            `SEQUENCE_NOT_FOUND` or `SEQUENCE_STEP_NOT_FOUND` - no such sequence
            in this workspace, or no such step on it.
          content:
            application/json:
              example:
                error: Step not found
                code: SEQUENCE_STEP_NOT_FOUND
        '405':
          description: Method not allowed - this path accepts GET, POST and PATCH
        '409':
          description: >-
            `SEQUENCE_BRANCH_CAMPAIGN_RUNNING` - leads have entered the
            campaign, which freezes the branch structure. Renaming a branch
            stays allowed.
          content:
            application/json:
              example:
                error: >-
                  You cannot add, remove or reorder branches once leads have
                  entered the campaign
                code: SEQUENCE_BRANCH_CAMPAIGN_RUNNING
        '429':
          description: Rate limit exceeded - 20 requests per 2 seconds per API key
components:
  schemas:
    ConditionBranch:
      type: object
      description: >-
        One branch of a condition step. Addressed by `sequenceId` - the
        sub-sequence its leads walk - never by position. The fields describing
        what the branch tests depend on the step's condition; the ones that do
        not apply are absent.
      properties:
        sequenceId:
          type: string
          description: >-
            The branch's sub-sequence id, and its address on every branch
            endpoint. Pass it to `POST /sequences/{sequenceId}/steps` to add
            steps inside the branch.
        index:
          type: integer
          description: >-
            Execution rank among the non-fallback branches, starting at 0. The
            first branch whose test matches takes the lead. Absent on the Else
            branch, which always runs last.
        fallback:
          type: boolean
          description: >-
            `true` on the Else branch - the one that catches every lead no other
            branch matched. Absent on the others.
        key:
          type: string
          description: >-
            The condition the step tests. Every branch of a step shares it: a
            branch never carries a condition of its own.
        name:
          type: string
          description: >-
            The branch's display name, present only when someone has set one.
            lemlist labels the unnamed ones "Branch 1", "Branch 2", … and
            "Else"; those defaults are not stored and are not returned here.
        delay:
          type: integer
          description: >-
            Length of the time window the condition waits on the lead's action,
            in days. Only on the lead-action conditions that store one.
        delayType:
          type: string
          enum:
            - within
            - waitUntil
          description: >-
            How the condition waits: `within` branches once the window is over,
            `waitUntil` parks the lead until the action happens, with no time
            bound.
        scoreComparator:
          type: string
          enum:
            - $gte
            - $lt
          description: >-
            `hasScore` only - how the lead's score is compared to
            `scoreThreshold`.
        scoreThreshold:
          type: integer
          description: '`hasScore` only - the score this branch tests against.'
        emailStatusFilter:
          type: array
          items:
            type: string
            enum:
              - deliverable
              - risky
              - undeliverable
              - unverified
          description: '`hasEmailAddress` only - the email statuses this branch matches.'
        callStatusFilter:
          type: array
          items:
            type: string
          description: '`aircallDone` only - the call-status keys this branch matches.'
        customField:
          type: string
          description: >-
            `customLeadInfo` only - the tested field, normalized: a lead
            variable reads back as `variables.<name>`, a contact field as
            `fields.<name>`. Every branch of the step tests the same field.
        customOperator:
          type: string
          enum:
            - equal
            - contains
            - empty
            - notEmpty
          description: >-
            `customLeadInfo` only - how the field is compared to the tested
            values.
        customValues:
          type: array
          items:
            type: string
          description: >-
            `customLeadInfo` only - every value this branch tests; the branch
            matches when any of them does. Empty for the `empty` and `notEmpty`
            operators.
        selector:
          type: string
          description: >-
            The raw stored condition selector, as JSON. Returned only when none
            of the fields above could describe the branch.
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic

````