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

# API Relays

> Forward requests to external APIs through Curator, keeping credentials secure and centralizing access control.

## Overview

An API relay is a server-side proxy that sits between your users and an external API, letting Curator call
third-party services without exposing credentials to the browser. You configure the relay once; Curator then
attaches your stored credentials, validates incoming calls, and forwards the assembled request to the external
service on the caller's behalf.

The result: sensitive credentials never leave your server, your external API surface is limited to exactly what
you expose, and you get a single, auditable integration point you can monitor, update, or disable without
touching the calling code.

## When to use an API relay

API relays bridge Curator with any third-party API. Common scenarios:

* **Custom BI embeds from non-integrated platforms** — a custom JavaScript embed that fetches live data from an
  external REST API, with the API key stored as a Curator constant instead of in the browser.
* **Submitting form data to a webhook** — Data Manager routes mark-commenting submissions to any HTTP endpoint,
  using an API relay as the connection point. See [Sending Data to Webhooks](/embedding_using_analytics/data_manager/sending_data_to_webhooks).
* **AI chat integration** — let users talk to an AI assistant without exposing your paid AI account credentials.

## Prerequisites

API relays require the **Integration Automation** feature to be enabled:

1. Log in to the Curator backend.
2. Navigate to **Settings** > **Portal Settings** > **Features**.
3. Enable **Integration Automation** under the Functionality section.
4. Save and refresh the page.

After enabling, the **Integrations** > **Automation** > **API Relay** section will appear in the left-hand menu.

## Creating an API relay

1. Navigate to **Integrations** > **Automation** > **API Relay**.
2. Click **New** at the top of the list.
3. Fill in the form (see the field reference below) and click **Save**.
4. Once saved, the **Link** shown at the top of the edit form is the URL you will call to trigger
   the relay. Copy it and use it in your integration.

> **Security note:** The Portal Link is publicly accessible by default — any caller who knows the URL can trigger
> the relay, and it is not tied to a logged-in user. If the relay exposes a sensitive upstream API, restrict
> access (see [Securing a relay](#securing-a-relay) below).

## Field reference

### Basic settings

| Field                | Description                                                                                                                                                                                               |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name**             | A descriptive label for the relay. Used only in the backend list — not exposed to callers.                                                                                                                |
| **Description**      | Optional free-text notes. Useful for documenting what the relay does and who relies on it.                                                                                                                |
| **Log Relay Usage?** | When enabled, Curator writes a log entry every time the relay is triggered. Includes the incoming input, outgoing request details, and the response. Useful for debugging but may be noisy in production. |

***

### Outgoing Request URL

This section controls where Curator sends the relayed request.

| Field                    | Description                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **URL**                  | The full external API endpoint URL. Do not include a query string here, variables and constants are appended automatically.                                                                                                                                                                                                                                        |
| **Allow Dynamic URL**    | When enabled, a caller can supply a different target URL at call time via the variable name set in **Dynamic URL Variable**. If the caller omits the variable, the static URL above is used.                                                                                                                                                                       |
| **Dynamic URL Variable** | The query parameter name the caller should use to pass an override URL. Only shown when **Allow Dynamic URL** is enabled.                                                                                                                                                                                                                                          |
| **Used In Webhook?**     | Changes how the outgoing request body is constructed. When enabled, Curator forwards the entire incoming request body to the upstream URL rather than only the configured variables and constants. Enable this when the relay will be selected in a Data Manager Data Group's **Send to Webhook** setting, where the full submitted payload needs to be forwarded. |

***

### Outgoing Request Content

This section defines what Curator sends to the external API: the headers, fixed values, caller-supplied values,
and body content.

#### Headers

HTTP headers to attach to every outgoing request (e.g. `Content-Type: application/json`, `Accept: application/json`).
Each header entry has a **Key**, a **Value**, and an **Allow Dynamic Values** toggle. When dynamic values are enabled,
a caller can override that header's value by sending an HTTP header of the same name in their request to the relay.

#### Constants

Fixed key-value pairs that are always sent with the outgoing request regardless of what the caller provides.
This is the right place for credentials, API keys, tokens, or any other value that must remain server-side and
must never be visible to the caller. Constants cannot be overridden by incoming requests.

#### Variables

Named parameters that the caller is expected to supply at call time (e.g. `start_date`, `region`, `user_id`).
Each variable has a **Key** (the parameter name) and an **Is Required?** toggle. Required variables will cause
the relay to reject the call if they are missing. Variables are passed by the caller as query string parameters
or POST body fields using the same key name defined here.

#### Body Content

Static body content to include in the outgoing request (e.g. a fixed JSON or XML payload). Leave blank if the
request body is built entirely from variables and constants. Body content applies to POST relays only — a GET
relay sends its parameters on the URL and ignores the body.

To let an incoming request set or edit the body at call time — whole-body replacement, placeholder substitution,
or transforming the value before it is injected — enable **Allow Dynamic Body Content**. This is covered in full
in [Dynamic Body Content in the API Relay](/embedding_using_analytics/data_manager/api_relay_dynamic_body_content).

***

### Incoming Request Validation

Optional rules that Curator evaluates before forwarding any request. If a request fails validation, the relay
is not called and Curator returns an error.

#### Header-based validation

Define conditions on specific HTTP headers in the incoming request. For each rule, specify:

* **Header** — the HTTP header name to inspect.
* **Condition** — one of: Matches, Does not match, Contains, Does not contain, Starts with, Ends with.
* **Value** — the value to test against.

All defined rules must pass for the relay to proceed.

#### Variable-based validation

The same conditional structure applied to query string or POST body parameters rather than headers.

#### Validation failure response

By default, a validation failure returns an **HTTP 403** response. Disable **Should validation failures respond
with error code?** to return an **HTTP 200** with an error message in the body instead. Some webhook endpoints
or client-side integrations expect 200 for all responses; use this toggle if the caller cannot handle 4xx
status codes.

***

## Securing a relay

The relay endpoint is public and unauthenticated — it does not require a logged-in user, and any caller who
knows the Portal Link can trigger it. Your credentials stay safe (they live in **Constants**, server-side), but
the endpoint itself is open. To lock it down:

* **Require a shared secret (recommended).** Add an **Incoming Request Validation** rule that checks for a header
  or variable only authorized callers know — e.g. a header `X-Relay-Token` with condition **Matches** and a
  long random value. Requests without it are rejected before the relay forwards anything.
* **Restrict by IP at the network layer.** Curator has no built-in per-relay IP allowlist. To limit the relay to
  specific source IPs, enforce it in front of Curator — in your web server (nginx/Apache), load balancer,
  firewall, or WAF — by allowing only trusted IPs to reach the `/api/v1/integration/apiRelay` path. Do not rely
  on a validation rule against a forwarded header such as `X-Forwarded-For`: that header is caller-supplied and
  can be spoofed.

## Calling the relay

Once a relay is saved, Curator generates a **Portal Link** shown at the top of the edit form. This is the
URL you call to trigger the relay. Its structure is:

```
https://your-curator-instance.com/api/v1/integration/apiRelay?api_relay_id=X&variable1=X&variable2=X
```

* `api_relay_id` is the numeric ID of the relay record (fixed).
* Each configured **Variable** appears as a query parameter.

The relay accepts both **GET** and **POST** requests. For POST, variables can be supplied in the request body
instead of the query string.

### Response format

Curator returns a JSON object in all cases. The shape depends on whether the relay succeeded, failed, or was
blocked by validation.

**On success:**

```json theme={null}
{
  "result": "Success",
  "msg": { ... }
}
```

| Field    | Description                                                                      |
| -------- | -------------------------------------------------------------------------------- |
| `result` | `"Success"` or `"Failure"`.                                                      |
| `msg`    | The external API's response body — parsed if it is JSON, otherwise a raw string. |

**On failure** — `result` is `"Failure"` and `msg` is a human-readable error. This covers both relay-level
problems (missing or invalid `api_relay_id`, a missing required variable) **and** upstream API errors: if the
external API responds with an HTTP status of 400 or higher, the relay reports failure with a message like
`There was an error processing your request: API Relay call failed with HTTP code 500`.

```json theme={null}
{
  "result": "Failure",
  "msg": "There was an error processing your request: ..."
}
```

**When Incoming Request Validation blocks the call:**

```json theme={null}
{
  "status": "error",
  "msg": "Invalid incoming request for API relay"
}
```

Validation failures use a different envelope (`status` instead of `result`) and return HTTP 403 by default (or
HTTP 200 if you have disabled the **Should validation failures respond with error code?** toggle).

***

## Good to know

* **Constants are never exposed to callers.** They are stored server-side and merged into the outgoing request
  by Curator. A caller inspecting browser network traffic will only see the Curator relay URL and their own
  variables — not the upstream API credentials.

* **Variable names are pass-through.** A variable named `start_date` in the relay configuration must be sent
  as `start_date` in the incoming request. Curator does not rename or transform variable names — only dynamic
  body content advanced processing can modify values.

* **Headers sent by the caller are not forwarded by default.** Only headers you explicitly define in the
  **Headers** section are included in the outgoing request. This prevents accidental forwarding of cookies,
  session tokens, or other browser headers to the external API.

* **Relay calls are unauthenticated by default.** Curator does not require the caller to be a logged-in user to
  hit the relay endpoint — see [Securing a relay](#securing-a-relay) if you need to restrict access.

* **Enabling Log Relay Usage adds full request/response logging.** This is useful during development and
  debugging but can be verbose. Logs are written to Curator's standard application log files under
  `storage/logs/`. Disable logging in production once the integration is confirmed working.

* **The relay is a thin forwarder.** It returns the upstream response body largely as-is (parsing it if it is
  JSON) rather than reshaping it. The one thing it does act on is the upstream HTTP status: a 400-or-higher
  response is turned into a `"Failure"` envelope rather than passed through as a success.

***

## Related

* [Sending Data to Webhooks](/embedding_using_analytics/data_manager/sending_data_to_webhooks) — how to connect
  an API relay to Data Manager for mark-commenting webhook submissions.
* [Dynamic Body Content in the API Relay](/embedding_using_analytics/data_manager/api_relay_dynamic_body_content) —
  letting an incoming request set or edit the outgoing request body.
