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

# API Node

<div className="block dark:hidden">
  <Frame>
    <div className="p-1">
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-cover.svg?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=9315a456fc5a28f88bcc7b8416a23e76" alt="API node interface on light mode" className="rounded-[14px]" width="1048" height="720" data-path="images/dark_mode/api-action-cover.svg" />
    </div>
  </Frame>
</div>

<div className="hidden dark:block">
  <Frame>
    <div className="p-1">
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-cover.svg?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=9315a456fc5a28f88bcc7b8416a23e76" alt="API node interface on dark mode" className="rounded-[14px]" width="1048" height="720" data-path="images/dark_mode/api-action-cover.svg" />
    </div>
  </Frame>
</div>

The **API node** runs an HTTP request automatically when the flow reaches it, letting your Pearl pull or push data from an external system. Depending on where you place it, it behaves in one of three ways:

* **Pre-Call API**: runs once, before the conversation starts.
* **In-Call API**: runs during the conversation, when the flow reaches the node.
* **Post-Call API**: runs after the conversation ends, as a post-call action.

The configuration form is the same in all three cases. Only the available variables, the response handling, and the transitions differ (see [Context Differences](#context-differences)).

***

## Adding an API Node

| Context           | Where to add it                                                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| **Pre-Call API**  | On the **Start** node, choose **Pre Call API**. It is inserted between Start and the Opening Sentence, and runs before the call.      |
| **In-Call API**   | Add an **API** node from the side toolbar (or the node picker under *Live Action Nodes*) and connect it where the request should run. |
| **Post-Call API** | On the **Post-Call Actions** container (reached from an End Call transition), click **Add Action** and choose **API**.                |

***

## Configuring the Request

<Steps>
  <Step title="Description">
    Explain what this API does and what data it returns (e.g. *"Fetches customer order history"*). Maximum **150 characters**. This helps Pearl understand when and how to use the action.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-description.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=47845ce87a720876b28aafbba59ea87a" alt="API node description field" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-description.png" />
    </Frame>
  </Step>

  <Step title="URL & Method">
    Type the API endpoint URL and choose the **HTTP Method** (**GET**, **POST**, **PUT**, **DELETE**, or **PATCH**) depending on the API's requirements. Click **+** to insert a variable into the URL, limited to the variables available in the node's context (see [Context Differences](#context-differences)).

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-url.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=23d972380e13615678154e654bf951e1" alt="API URL and method configuration" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-url.png" />
    </Frame>

    <Info>
      The available fields depend on the method:

      * The **Body** section is shown only for **POST**, **PUT**, and **PATCH** (hidden for GET and DELETE).
      * The **Response Output Schema** is available for every method **except DELETE**.
    </Info>
  </Step>

  <Step title="Headers">
    Add any header required by the API, such as `Content-Type` or `Authorization`. Header values are **static**.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-headers.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=5a5fd4845ccddde57fedb3130ff6d1b2" alt="API headers configuration" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-headers.png" />
    </Frame>

    <Info>
      For a **dynamic authorization token**, use a [**Credential**](#credentials-authentication) instead of a static header.
    </Info>
  </Step>

  <Step title="Body (POST / PUT / PATCH)">
    Provide **Key / Value** pairs, sent as JSON.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-body.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=6c489ee6ab681d99fe8c5a7a6fd3abc7" alt="API body configuration" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-body.png" />
    </Frame>

    Each **Value** is either a **Variable** or a **Static & Custom** value. Static values support these types:

    | Type               | Format                 |
    | ------------------ | ---------------------- |
    | **Text**           | String                 |
    | **Whole Number**   | Integer                |
    | **Decimal Number** | Float / double         |
    | **Boolean**        | `true` / `false`       |
    | **Date**           | Calendar date          |
    | **Time**           | Time of day            |
    | **Date & Time**    | Combined date and time |

    <Info>
      For each row you can toggle a **Required** checkbox:

      * **Checked**: Pearl prompts the customer for the value before sending the request if it hasn't been collected yet.
      * **Unchecked**: the request is sent even if the value is missing; the key is simply omitted.
    </Info>

    When using a variable in the body, be aware that:

    * The platform **casts each variable to its configured data type** (e.g. Whole Number becomes an integer, Text is quoted as a string). A type mismatch may cause the API to reject the request.
    * You can mix static values and variables in the same body.
    * For nested JSON, use **dot notation** in the Key (`customer.address.street`) and **square brackets** for array indices (`order.items[0].productId`). See [Using Nested Objects](#using-nested-objects) below.
  </Step>
</Steps>

### Using Nested Objects

Many APIs expect a **nested JSON structure** in their request body. Use dot notation and array indices in the **Key** column to build nested payloads while keeping them organised and readable.

<Card title="How to define nested keys">
  * Use **dot notation** for properties (`customer.address.street`)
  * Use **square brackets** for array indices (`order.items[0].productId`)

  <Info>
    You can pair nested paths with any variable type: Text, Number, Boolean, etc.
  </Info>

  Mapping table:

  | API key                    | Variable        |
  | -------------------------- | --------------- |
  | `customer.name`            | `customerName`  |
  | `customer.email`           | `customerEmail` |
  | `customer.address.street`  | `street`        |
  | `customer.address.city`    | `city`          |
  | `order.items[0].productId` | `productId`     |
  | `order.items[0].quantity`  | `quantity`      |

  Resulting body:

  ```json body.json theme={null}
  {
    "customer": {
      "name": "{{customerName}}",
      "email": "{{customerEmail}}",
      "address": {
        "street": "{{street}}",
        "city": "{{city}}"
      }
    },
    "order": {
      "items": [
        {
          "productId": "{{productId}}",
          "quantity": "{{quantity}}"
        }
      ]
    }
  }
  ```
</Card>

***

## Response Output Schema & Variable Assignment

<Warning>
  API responses are capped at **10,000 characters**. Anything longer is automatically truncated.
</Warning>

Available for every method **except DELETE**. The **Response Output Schema** lets you filter the API response so only the relevant data flows back into the conversation. Without filtering, the entire JSON is returned, which can reduce precision because the AI receives too much unrelated information. Even for small responses, setting a schema is strongly recommended to keep Pearl focused.

Each row of the schema has three parts:

| Column                  | Description                                                                             |
| ----------------------- | --------------------------------------------------------------------------------------- |
| **Required** (checkbox) | Mark the path as mandatory for the action.                                              |
| **JSON Path**           | The path to extract from the response.                                                  |
| **Variable to Assign**  | Store the extracted value in a variable. **Required for Pre-Call**, optional otherwise. |

<Frame>
  <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-response-output-schema.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=03e45995d9650e207c8c1f7ef1216193" alt="API response output schema configuration" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-response-output-schema.png" />
</Frame>

### How it works

* Provide a list of **JSON Path** strings.
* The system extracts only those paths from the API response; everything else is discarded.

<Check>
  Benefits:

  * Keeps the response size small
  * Improves the quality and relevance of AI outputs
  * Prevents hitting the 10,000-character truncation limit
  * Ensures only the necessary fields are carried into the next steps of the conversation
</Check>

<Card icon="circle-info" iconType="light">
  ### Assigning to a variable

  Key things to know:

  * **The variable's type must match the data type returned by the API at that path.**
  * If the value returned is a list, make sure the variable is configured to **allow multiple values**.
  * A variable can store up to **600 characters**. Any data beyond this limit is **truncated**.

  <Info>
    Outside of Pre-Call APIs, assigning a variable is optional. If you don't assign one, the filtered JSON is still available for the conversation's internal logic, but it won't be stored for later reuse.
  </Info>
</Card>

***

## Credentials (Authentication)

If your API requires authentication, create a **Credential** on the platform, then enable the **Credentials** toggle in the API node and select it from the **Token** dropdown (use **Add New** to create one, **Edit** to update it). Leave the toggle off if no authentication is needed.

<Frame>
  <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-credential-toggle.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=52183ab02f33bb33b8b690150d35b35b" alt="API credentials toggle and token selection" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-credential-toggle.png" />
</Frame>

**Supported credential types** (chosen from the **Type** dropdown when creating a credential):

| Type               | Description                                              |
| ------------------ | -------------------------------------------------------- |
| **Api Key**        | Injected in a **Header** or **Query** parameter          |
| **Basic Auth**     | Username + password                                      |
| **Bearer**         | A static bearer token                                    |
| **Custom Api Key** | Custom headers / query params / body                     |
| **Refresh Token**  | The platform fetches and refreshes a token automatically |

<Info>
  **OAuth2** providers are connected through [**Integrations**](/pages/pearl_vibe), not created manually in this form.
</Info>

<Tip>
  Why use a Credential?

  * Avoid hardcoding tokens manually in every API node
  * Automatically refresh tokens based on their TTL (time-to-live)
  * Centralized management when multiple API nodes reuse the same token
  * No need to parse token responses manually, the platform extracts the token for you
</Tip>

### Configuring a Refresh Token credential

<Steps>
  <Step title="Open the Credential Manager">
    Open the **Credential Manager** from the icon at the top of the Flow Editor header.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-credential-1.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=ab0b78e1cdf297371c3b0cbbf96ff17f" alt="Credential Manager access in the Flow Editor header" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-credential-1.png" />
    </Frame>
  </Step>

  <Step title="Add a new credential">
    In the **Credentials Manager**, click **+ Add** to create a new credential.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-credential-2.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=d71edf3215d4b8f46ff65779515b88f0" alt="Add a new credential in the Credentials Manager" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-credential-2.png" />
    </Frame>
  </Step>

  <Step title="Choose how to add it">
    You can either pick a ready-made **integration** from the list (Google, Microsoft, Slack, HubSpot, Salesforce, Zoho, and more) to connect through its guided flow, or click **Add Manually** to configure a custom credential such as a **Refresh Token**.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-credential-3.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=0694f23aafe2d3b3f1041ac824d0afe8" alt="Choose an integration or add a credential manually" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-credential-3.png" />
    </Frame>
  </Step>

  <Step title="Fill in the credential details">
    If you chose **Add Manually**, enter a **Name** (a label to identify it later) and select a **Type**. The form updates to show the fields specific to the selected type.

    <Frame>
      <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-credential-4.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=f4dbc4e34b5f8414b2b1cbd842a67e08" alt="Manual credential form with name, type, and type-specific fields" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-credential-4.png" />
    </Frame>

    <Card title="Example: Refresh Token fields">
      | Field                 | Description                                                                                                                                                     |
      | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
      | **Access Token URL**  | The method and endpoint used to request the token, with optional **Headers**, **Query Params**, and **Body** (e.g. `grant_type`, `client_id`, `client_secret`). |
      | **Token Path**        | JSON path to locate the token in the response (e.g. `data.access_token`).                                                                                       |
      | **TTL (sec)**         | Token time-to-live (minimum **100**).                                                                                                                           |
      | **Header Key**        | Name of the header where the token is injected (e.g. `Authorization`).                                                                                          |
      | **Header Prefix**     | Optional prefix for the token (e.g. `Bearer`).                                                                                                                  |
      | **Secured Variables** | Sensitive key/value pairs reused across requests.                                                                                                               |
    </Card>
  </Step>

  <Step title="Test the Credential">
    Use **Test Credentials** to call the token endpoint and preview the JSON response, confirming your configuration retrieves the token successfully before saving.
  </Step>
</Steps>

<Card icon="circle-info" iconType="light">
  ### How the Credential is used

  Once saved, select this Credential from the **Token** dropdown in any API node. When selected:

  * The platform automatically adds the token to the request header, using the configured **Header Key** and optional **Header Prefix**.
  * The token is refreshed automatically when it expires, based on the configured **TTL**.

  <Warning>
    Make sure the **Token Path** matches the exact location of the token in the JSON response. If the platform can't find the token at this path, the Credential will fail.
  </Warning>
</Card>

***

## Context Differences

The same API node behaves differently depending on where you place it in the flow.

| Aspect                          | Pre-Call API                     | In-Call API            | Post-Call API                  |
| ------------------------------- | -------------------------------- | ---------------------- | ------------------------------ |
| **When it runs**                | Before the call                  | During the call        | After the call                 |
| **Available variables**         | Pre-Call only                    | Pre-Call + In-Call     | Pre-Call + In-Call + Post-Call |
| **Assign response to variable** | Required                         | Optional               | Optional                       |
| **Transitions**                 | Success (+ optional Not Success) | Continue / conditional | None                           |
| **Can duplicate**               | No                               | Yes                    | —                              |

<Tabs>
  <Tab title="Pre-Call API">
    Runs **once before the conversation begins**. Typical uses:

    * **Inbound**: look up the caller using the auto-captured **phone number** and **call id**.
    * **Outbound**: preload data from Pre-Call variables already stored on the lead.

    <Info>
      Only **Pre-Call variables** are available (system variables like phone number, call id, first/last name, email, plus your own Pre-Call variables).
    </Info>

    * **Assigning response values to variables is required**, that's how pre-call data becomes usable in the conversation. All required variables must be returned for the node to take the **Success** path.
    * **Transitions**: a **Success** branch by default. Enable **On Error Transition** (in the Transitions tab) to add a **Not Success** branch for failed requests.
    * Pre-Call API nodes **cannot be duplicated**.
  </Tab>

  <Tab title="In-Call API">
    Runs **when the flow reaches the node during the conversation**.

    * Both **Pre-Call** and **In-Call** variables are available.
    * After it runs, the flow follows the **Continue** transition (or your conditional transitions).
    * Assigning response values to variables is optional but recommended for reuse later in the flow.
  </Tab>

  <Tab title="Post-Call API">
    Runs **after the call**, as part of the **Post-Call Actions**.

    * All variable groups are available, including **Post-Call** variables (call time, summary, recording, duration, transcript).
    * Post-Call actions have **no transitions**.
  </Tab>
</Tabs>

***

## Testing Your API

Use the **Test API** panel below the form:

<Frame>
  <img src="https://mintcdn.com/nlpearl/zHQFKodWEnahK9ly/images/dark_mode/api-action-test.png?fit=max&auto=format&n=zHQFKodWEnahK9ly&q=85&s=a440ef191affb74ce4fe02c68f497a82" alt="Test API panel" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/api-action-test.png" />
</Frame>

<Steps>
  <Step title="Assign Test Values">
    Give sample values to every variable used in the request.
  </Step>

  <Step title="Send">
    Click **Send** to run the request.
  </Step>

  <Step title="Inspect">
    Review the raw response, the filtered response (if an Output Schema is set), and any variables populated from it.
  </Step>
</Steps>

<Tip>
  Use **Expand** to open a full-screen view with the request and response side by side. Test and perfect your setup before putting the Pearl in production.
</Tip>

***

<CardGroup cols={1}>
  <Card title="Variables" icon="square-root-variable" iconType="light" href="/pages/variables">
    Learn how to create and use variables inside API nodes.
  </Card>
</CardGroup>
