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.
- 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:- Log in to the Curator backend.
- Navigate to Settings > Portal Settings > Features.
- Enable Integration Automation under the Functionality section.
- Save and refresh the page.
If you can see the Automation menu but not API Relay, Integration Automation is already enabled, and your
account has another Integration permission but not Manage API relay. Ask an administrator to grant it.
Creating an API relay
- Navigate to Integrations > Automation > API Relay.
- Click New at the top of the list.
- Fill in the form (see the field reference below) and click Save.
- 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 below).
Field reference
Basic settings
Outgoing Request URL
This section controls where Curator sends the relayed request.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. Each constant also has an Encrypt Value toggle. Turn it on for sensitive values such as API keys or client secrets: the value is then stored encrypted in the database and shown as***redacted*** in relay logs instead
of in plain text. The outgoing request still receives the real value.
Encryption is one-way. Once saved, the form only ever shows the encrypted form of the value, and Curator never
decrypts it back for display. Turning Encrypt Value off while the encrypted value is still in the field is
rejected when the relay is saved. To store a constant unencrypted again, clear the field and enter a new value.
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.Response Caching
Optional. A relay makes a fresh outgoing request on every call by default. Turn on caching when the same response is valid for more than one caller or more than one moment, so repeated calls skip the round trip to the upstream API.- Cache Relay Responses? — off by default. When on, Curator stores the upstream response and reuses it for
any later call that would have produced the same outgoing request. Calls that differ in their HTTP method or
in the parameters they send are cached separately; parameter order does not matter, so
?a=1&b=2and?b=2&a=1share one cached response. - Cache Duration (seconds) — how long a cached response stays valid. Defaults to 60. Keep this shorter than the lifetime of anything the response contains: a relay that returns a short-lived OAuth token should expire its cache well before the token does.
- Cache Per User? — off by default, which is correct when every caller legitimately receives the same response, such as a client credentials OAuth flow. Turn it on when the upstream response differs per user. Curator then keeps a separate cached response for each signed-in user, and any call it cannot attribute to a specific user is not cached at all — including calls to the relay’s own unauthenticated URL, and every call on a portal using Pass-Through authentication, where all visitors share one identity.
- Webhook relays. A webhook forwards the incoming payload upstream as a write, so replaying an earlier response would silently drop a repeated submission.
- Requests carrying a file upload, which cannot be matched against an earlier call.
- Requests that fail Incoming Request Validation, which are rejected before the cache is consulted.
Access
- Require a Curator Session? — off by default, and on for relays an AI assistant creates through MCP. When on, the relay only answers visitors who are signed in to Curator, on the site or in the backend. Anyone else gets an HTTP 401 response and the relay does not call the external API. Turn this on for relays that Curator pages and embedded HTML call. Leave it off for relays that outside systems call, such as webhooks, because those callers have no Curator session. It also refuses requests that another website makes from a signed-in visitor’s browser, with an HTTP 403 response. On a portal that uses Pass-Through authentication, every visitor counts as signed in, so this setting only refuses those cross-site requests there.
- Available to MCP Tools? — on by default. When on, AI assistants connected with a Curator MCP token can see, change, and call this relay, acting as the backend user who owns the token. That user also needs the Manage API relay permission. See Curator MCP Server. Turn this off to hide the relay from every MCP token.
- Callable from Embedded HTML? — off by default, and on for relays an AI assistant creates through MCP. When
on, HTML files embedded on Curator pages can call this relay with
curatorApiRelay()(see From embedded HTML). Any embedded HTML file can ask for any relay, so only turn this on for relays meant to be used that way. Calls from embedded HTML to a relay without it get an HTTP 403 response.
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.
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
Unless Require a Curator Session? is on, 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 Curator session (for relays that Curator pages call). Turn on Require a Curator Session? so only signed-in Curator users can call the relay. Pages and embedded HTML keep working, because they call the relay as the signed-in viewer.
- Require a shared secret (for relays that outside systems call). Add an Incoming Request Validation rule that checks for a header
or variable only authorized callers know — e.g. a header
X-Relay-Tokenwith 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/apiRelaypath. Do not rely on a validation rule against a forwarded header such asX-Forwarded-For: that header is caller-supplied and can be spoofed. - Avoid Allow Dynamic URL on relays with credentials. A relay with Allow Dynamic URL on sends its Headers and Constants to any path the caller supplies on the relay’s host, so any caller can use your credentials against every endpoint of that API. That includes AI assistants with MCP access when Available to MCP Tools? is on. Leave Allow Dynamic URL off on relays that hold credentials, or lock the relay down with the options above and turn off Available to MCP Tools?.
- Redirects stay on the relay’s host. A relay follows a redirect only to the same host (an
httprelay may move tohttpson that host). A redirect to any other host fails the call instead, so set the relay’s URL to where the redirect leads.
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:api_relay_idis the numeric ID of the relay record (fixed).- Each configured Variable appears as a query parameter.
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:
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.
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).
When the relay requires a Curator session and the caller is not signed in: HTTP 401 with
This API relay only answers requests from Curator's own pages.
From embedded HTML
An HTML file can call a relay when a page shows it in a sandboxed frame, which is isolated from Curator. Show the file in a sandboxed frame in either of these ways:- On a page, add a File element, set File type to Embed, select the HTML file, and turn on
Sandbox HTML (allow API relays). The switch is off by default, and an embed without it is not sandboxed,
so
curatorApiRelayis not defined in it. - Create a page from the HTML file. Pages created this way are sandboxed.
curatorApiRelay function that calls the relay through the page, as the signed-in viewer. The relay must have
Callable from Embedded HTML? turned on:
- The first argument is the relay ID and the second holds the relay’s variables. Pass
{method: 'POST'}as a third argument to send a POST. - The function returns a promise of the external API’s response (the
msgvalue above), already parsed when it is JSON. When the call fails, the error has amessageand astatus. Thestatusis the HTTP status of the relay’s own response, described above, not the external API’s: 401 when the relay requires a session, and 200 when the external API failed. The external API’s code is in the message instead. - Because the call runs as the viewer, it works with relays that have Require a Curator Session? turned on.
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_datein the relay configuration must be sent asstart_datein 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 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/. Constants flagged with Encrypt Value are redacted from these logs (shown as***redacted***) in the logged arguments and outgoing URL, and are also scrubbed the same way from the logged upstream response, from the curl connection’s effective and redirect URLs, and from its Content-Type response header when those echo the value back verbatim or URL/JSON-encoded. Other connection details (status code, timings) are not scrubbed, since they cannot carry a constant’s value. An encrypted value that cannot be matched safely in free-form content — too short, or one that happens to match Curator’s own***redacted***marker — has the response and those three fields replaced by an***omitted...***placeholder instead; the arguments and outgoing URL are still logged with the value redacted either way. Scrubbing only catches an upstream echoing the value itself: a response that returns the value transformed (for example base64-encoded, hashed, or embedded in a derived token) is not detected, so still 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. -
[Grouped] API Relay X was usedin the Event Log is log grouping, not a cap on relay calls. When the same Event Log message repeats often enough, Curator stops writing a separate line for every occurrence and logs one entry standing in for the duplicates instead — see Log Rate Limiter. Grouping does not throttle or block the relay, and there is no per-relay limit to raise. Relay calls only share the API rate limits. Read it as a signal that something is repeating: open the grouped entry for the count and the time it started, and look at the entries logged before grouping began to find the underlying error. Turning on Log Relay Usage? temporarily captures the request and response detail behind those entries.
Related
- 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 — letting an incoming request set or edit the outgoing request body.