> For the complete documentation index, see [llms.txt](https://docs.uptiq.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.uptiq.ai/platform-resources/skill-library/logic-and-data-integration/api-call.md).

# API Call

**API Call** invokes any external HTTP/HTTPS endpoint and passes the response — or the failure details — to the next skill. It is the general-purpose way for an agent to reach systems that aren't in the [Apps & Services](/agent-builder/build/apps-and-services.md) or [MCP Tools](/agent-builder/build/mcp-tools.md) catalogs.

When a service *is* in one of those catalogs, start there: the connector handles authentication for you. API Call is the escape hatch for everything else — your CRM, a payment gateway, a proprietary legacy system.

## How it works

* **Input resolution** — `$input` (the previous skill's output) and `$secret` (vault secrets) can be referenced in any templatable field: the URL, headers, or body.
  * `https://api.example.com/users/$input.userId`
  * `Authorization: Bearer $secret.token`
* **Request assembly** — endpoint, query parameters, headers, and body are composed from the configuration.
* **Execution** — a **blocking** HTTP call. It always waits for completion, and this does not change between synchronous and asynchronous workflow modes.
* **Response:**
  * **Success** — emits the data payload.
  * **Failure** — fills `error`, `statusCode`, `statusText`; `data` may be `null`.

## Worked example: notifying your CRM of a new client

A workflow processes a loan application. Once it's approved, the CRM needs the new client's details so the sales or service team can pick up the next step.

**The problem.** Re-keying client data from the application into the CRM is repetitive, slow, and a reliable source of errors.

**The approach.** After the approval step, an API Call sends the client's details straight to the CRM.

**1. Point it at the CRM.** In **Endpoint**, enter the URL your CRM exposes for creating clients — `https://api.yourcrm.com/v1/clients`.

<figure><img src="/files/hDzLIxR2Hku2bbTajeTe" alt=""><figcaption><p>Defining the API endpoint</p></figcaption></figure>

**2. Choose the method.** You're creating a record, so select **POST**.

<figure><img src="/files/PStpDqJEim0oQo7Xg2xt" alt=""><figcaption><p>Choosing the HTTP method</p></figcaption></figure>

**3. Add headers.** Tell the CRM what you're sending: key `Content-Type`, value `application/json`.

<figure><img src="/files/Zj28glPWZpyPuMVaGU2l" alt=""><figcaption><p>Adding the Content-Type header</p></figcaption></figure>

**4. Map the data.** Select **Key-Value** (or **Raw Data** for complex JSON), then pull values from earlier steps:

* `firstName` → `$input.clientDetails.firstName`
* `lastName` → `$input.clientDetails.lastName`
* `email` → `$input.clientDetails.email`

**5. Authorize.** Select the auth type your CRM uses — API Key or Bearer.

<figure><img src="/files/JB1IOXF8EFoXSAbnyB7D" alt=""><figcaption><p>Setting up authorization with a secret variable</p></figcaption></figure>

{% hint style="warning" %}
**Always use a `$secret` variable for keys and tokens** — `$secret.CRM_API_KEY`, never the literal value. This keeps credentials out of the configuration, and lets you point test and production at different keys without editing the skill.
{% endhint %}

### Trying it before you ship it

The **Try Out** tab runs the skill in isolation, against your sample input, without touching the rest of the workflow. Supply the values an earlier step would have produced, run it, and read the JSON response.

* **`200`/`201`** — it worked. `data` holds the CRM's response and `error` is `null`.
* **`400`/`409`/`500`** — the call reached the CRM and was rejected. `error` explains why.
* **`0`** — a network problem. The call never arrived.

## Configuration reference

| Field           | Type                                 | Required | Description                                        |
| --------------- | ------------------------------------ | -------- | -------------------------------------------------- |
| `endpoint`      | string                               | ✅        | Absolute URL of the external HTTP/HTTPS endpoint.  |
| `method`        | `GET` \| `POST` \| `PUT` \| …        | ✅        | HTTP method.                                       |
| `headers`       | object\<string, string>              | —        | Extra request headers.                             |
| `params`        | object\<string, string \| string\[]> | —        | Query parameters. An array produces repeated keys. |
| `data`          | string \| object \| buffer           | —        | Request body.                                      |
| `dataFormat`    | `key-value` \| `raw`                 | —        | How the body is supplied.                          |
| `rawDataFormat` | `json` \| `text` \| `binary`         | —        | Encoding, when `dataFormat='raw'`.                 |
| `auth`          | object                               | —        | Authentication helper — see below.                 |

**Auth helpers:**

```json
// basic
{ "username": "...", "password": "..." }

// bearer
{ "token": "..." }

// apiKey — supports multiple header/value pairs
{ "headers": { "X-Client-ID": "...", "X-Client-Secret": "..." } }
```

**Multi-value query parameters.** `{ "params": { "dataId": ["123", "234", "4343"] } }` generates `?dataId=123&dataId=234&dataId=4343`.

## Output

| Field        | Type                    | Always | Description                             |
| ------------ | ----------------------- | ------ | --------------------------------------- |
| `data`       | any \| null             | —      | Parsed response body.                   |
| `statusCode` | number                  | ✅      | HTTP status — **`0` on network error**. |
| `statusText` | string                  | ✅      | Reason phrase, e.g. `OK`, `Conflict`.   |
| `headers`    | object\<string, string> | ✅      | Response headers, keys lower-cased.     |
| `error`      | string \| null          | —      | Error indicator; `null` on success.     |

**Success:**

```json
{
  "data": { "id": "inv_456", "amount": 1000, "status": "issued" },
  "statusCode": 201,
  "statusText": "Created",
  "headers": { "content-type": "application/json" },
  "error": null
}
```

**Failure — a duplicate invoice:**

```json
{
  "data": { "error": { "type": "duplicate_request", "message": "Invoice already exists" } },
  "statusCode": 409,
  "statusText": "Conflict",
  "headers": { "content-type": "application/json" },
  "error": "HTTP_ERROR"
}
```

{% hint style="info" %}
On an HTTP error, `data` still holds the external service's response body. The reason *why* the call failed usually lives there, not in `error` — which only says `HTTP_ERROR`.
{% endhint %}

## Errors

| Kind                    | `statusCode`                                   | `statusText`             | `error`                              | `data`                           |
| ----------------------- | ---------------------------------------------- | ------------------------ | ------------------------------------ | -------------------------------- |
| **Network / TLS / DNS** | `0`                                            | `""`                     | System message, e.g. `NETWORK_ERROR` | `null`                           |
| **HTTP ≥ 400**          | Echoes the status (`400`, `401`, `404`, `500`) | Echoes the reason phrase | `HTTP_ERROR`                         | The parsed response body, if any |

`statusCode: 0` is the tell for "the request never got there" — as opposed to "it arrived and was refused."

## Security

* **Never hard-code API keys or tokens** in the configuration. Inject them with `$secret` from the vault.
* Engine logs redact fields marked sensitive, including API Key and Authorization headers.

## Testing in isolation

* **Path** — `/skill-runtime/workflows/nodes/APICall/execute`
* **Method** — `POST`
* **Body:**

```json
{
  "nodeType": "API_CALL",
  "config": { },
  "input": { }
}
```

***

To add this skill to an agent, see [Adding a Skill to the Agent](/agent-builder/build/adding-a-skill-to-the-agent.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.uptiq.ai/platform-resources/skill-library/logic-and-data-integration/api-call.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
